
[title] Delete Customer
[path] Vendor Platform/Customer Accounts/

The **Customer Accounts** page allows you to manage all customer records associated with your platform. From this page, you can view account details, update information, or delete a customer if necessary.

### **Deleting a Customer**

To delete a customer:

1. Navigate to **Customer Accounts**.&#x20;
2. Select the account you want to manage.&#x20;
3. Click on the specific customer you wish to delete.&#x20;
4. On the right-hand side, click the **Delete (bin) button**.&#x20;
5. Confirm the deletion to remove the customer from the system.

See the screenshots below for reference:


![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/s2Ihr3J5MBP5U29AlGg-K_image.png "Customers List")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/AMeFAgDGwZyKwF-LHs2qS_image.png)


[title] License Check
[path] License API/


[title] Importing/Exporting Data
[path] Vendor Platform/


[title] Order Detail View
[path] Vendor Platform/Orders/

The order detail view allows you to lookup and modify information on a given order.

Actions you can take on the order view include:

- Exporting license/customer information for a given order
- Modifying order parameters (such as the order reference number or campaign parameters)
- Add more licenses to the order
- Add/edit customer to an order
- Add license managers to an order
- Delete the order

## Export CSV of Order Licenses

Click "export order data" and a CSV will be generated with information on the order, licenses, and customers.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8age7HWwFbglpOcOwm7uw_image.png)

## Edit Order Details

The fields you can modify include:

- Order reference number
- Campaign parameters
- Download ID
- Is this a test order
- Is this order a trial order



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/p92NYsPVOuecVgJsuTwET_image.png "Edit Order")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/1M40Z6f6xp4eT1xOwvhQL_image.png)

- Add more licenses to the order
- Add/edit customer to an order
- Add license managers to an order
- Delete the order

## Add or Edit the Customer for the Order

Click on the customer tab. If the order does not have a customer associated with it, you can add one from this screen. Otherwise, you can edit the existing customer.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/-BrAcFwfWI6N9HVm-V_cf_image.png)

## Add More Licenses to an Existing Order

Click on "Licenses" > "Issue new Licenses" to start the process of adding a new set of licenses. The rest of the license generation process should be very similar with the regular order creation process.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/FQ3CVTUjahNPd3LMhz6_t_image.png)

## Add a License Manager to an Order

:::hint{type="info"}
License managers can log in to the user portal and manage all licenses within an order, according to permissions they had been granted.
:::

Click on the "License manager" tab and press "Add license manager".&#x20;

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/a0w7JAA3reeXoABQKg1jU_image.png)

:::hint{type="info"}
Be sure to set up a notification to send the new license manager an email invite to the user portal, so that they can receive their initial email/password.
:::

Available permissions for license manager are:

| Manage license users            | Can add, edit or delete license users      |
| ------------------------------- | ------------------------------------------ |
| Manage license user credentials | Can change license users passwords         |
| Manage managers                 | Can add new license managers to some order |
| Reset device                    | Can reset device                           |
| Reset license                   | Can reset license                          |
| Borrow license                  | Can manage floating license borrowing      |
| Create bundle order             | Can create new product bundle orders       |
| Create order                    | Can create new orders                      |
| Issue license                   | Can issue new licenses on existing order   |

This permission can be edited only in enterprise pricing plan where they can be also extended with distribution portal permissions (creating orders and issuing licenses).

## Delete the Order

:::hint{type="danger"}
Deleting an order will also delete all of the licenses within it and the process is not reversible.
:::

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/H-TFdd9ZHnPg_CwdMtKvz_image.png)


[title] Add New Product
[path] Vendor Platform/Products/

### 1. Product Information

Fill in the following details about the new product:

![Product Details View](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/yLG2ENjQWV4LWgyrEes4o_image.png "Adding New Product")

- **Add New Bundle**: Group multiple products into a bundle.

Both actions can be done directly from this page for quick and seamless product management.

- **Product Name:** Enter the name of your product.
- **Product Code:** Enter a unique code for the product (e.g., "QQ").
- **Authorization Method:** Select the method for product authorization (e.g., License key).
- **Product has trial period:** *(Optional)* Check this box if the product offers a trial period.
  - **Trial Duration:** Specify the length and unit (days) of the trial period.
- **Product has file:** *(Optional)* Check this box if the product includes a downloadable file.

**Additional Product File Details**

If "Product has file" is checked, fill in the following fields:

- **Environment:** Select the environment (e.g., Linux, MacOS, Windows).
- **Initial Version:** Enter the initial version number (e.g., 1.0.717).
- **Release Date:** Set the release date for this version.
- **Link to Binary:** Provide a URL to the product’s binary file.
- **Link to Release Notes:** Provide a URL to the release notes file.
- **Link to EULA:** Provide a URL to the End User License Agreement file.
- **Channel:** Specify the release channel (e.g., prod, dev).

After completing the required fields, click the **Next** button to proceed and confirm by clicking create product button.

:::hint{type="info"}
You can create a product without checking **Product has trial period** and **Product has file**. These options are optional. In this example, both options are checked to demonstrate all available fields and properties.
:::

###


[title] Product Custom Fields
[path] Product Configuration/

:::hint{type="info"}
Starting with Platform Version **v3.222.0&#x20;**&#x43;ustom Fields support an allowed values List.
:::

Product custom fields allow you to define key\:value pairs for any product. For a given license, you can override the value of the product custom field with a license custom field value.

:::hint{type="info"}
When you add a custom field to a product, all licenses for that given product will have that field added to them, and will show up on license checks and activations. This field will appear on the server responses if you do not override the value for that given license.
:::

## Example Use-Cases for Custom Fields

There are many ways you can use custom fields.&#x20;

Here are a few example use-cases:

- Creating a product tier. The key might be something like "edition" and the default value could be the lowest tier, such a "lite". For a given license you may change the default with "standard" or "pro"
- Setting the number of CPU cores that a machine is allowed to run for your licensed application
- Setting a grace period for requiring online license checks

:::hint{type="info"}
We call a "Product Custom Field" the default key\:value pair that you set for a given product, and a "License Custom Field" the key\:value pair if you override the default value for the custom field for a given license.
:::

## Add/Remove/Edit Product Custom Fields

Open the product detail page, and click on the "custom fields" tab



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/5BttZ0FnQ-1T_XiTcJByx_image.png "Custom Fields Tab")

### Adding a New Product Custom Field

To add a new product custom field, Click "add custom field", and specify a name (key) and value for your new custom field:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/nUEhu6MAqy33sKfnROjN3_image.png)

### Modify/Delete Product Custom Field

Click on the pencil to edit an existing product custom field, and it will allow you to modify the name and/or the value.

Click on the red trash can to delete a product custom field.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/pn-IA36uPBen04FyQo81r_image.png)

:::hint{type="info"}
Once you issue a license, you can override the product custom field with a license custom field. You can edit the value of the custom field for any license that was issued.
:::

### Allowed custom field values

To enhance data consistency and prevent accidental input errors, LicenseSpring supports optional enumerated (enum) allowed values for custom fields defined at the product level. When allowed values are specified, only predefined values can be assigned to the corresponding license custom field.

This introduces an additional validation layer while preserving backward compatibility and flexibility.

### **Behavior and Logic**

| Condition                 | Allowed license custom field values                          |
| ------------------------- | ------------------------------------------------------------ |
| No allowed values defined | Any string                                                   |
| Allowed values defined    | Values in the list **OR** default product custom field value |

**1. Default behaviour (No allowed values defined)**

If a custom field on a product does not have an allowed values list defined:

- The associated license custom field can accept any string as its value. This allows full flexibility, including the ability to update or correct values without restriction.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/W7T-7BdWlo7WuVKFGBabL_image.png "Add Allowed Values")

**2. Allowed values defined on a product custom field**

If a custom field on a product has an allowed values list defined:

- The associated license custom field can only accept:
  - One of the list values, OR
  - The product custom field’s default value.

This restriction helps ensure data integrity by limiting inputs to known, validated values.

- If a **default value** is set, it is automatically added to the list of **Allowed Values**.&#x20;
- Users can **manually remove any allowed value**, including the current default (prompting selection of a new default).&#x20;
- The **default value must always be one of the allowed values**.&#x20;

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/zW_rWAp-jA3RH7Nak3Up0_image.png)

### Deletion of allowed values items

If a value (e.g., `val3`) is removed from the allowed values list on the product custom field:

- Existing license custom fields that already had `val3` set will retain this value.
- These values are not retroactively invalidated or overwritten.
- However, `val3` can no longer be set as a value in new license custom fields or updates.

This ensures stability and backward compatibility across issued licenses.

## **Configuration via Vendor Platform**

Allowed values for custom fields can be configured directly within the Vendor Platform or using the Management API.

When creating or editing a product custom field, vendors can:

- Leave the allowed values list empty to allow free-form values.
- Define a list of allowed values to enforce validation at the license level.
- Set a default value which remains valid even if not in the current allowed vlaues list.

![Product custom field allowed values](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/9rjyjtUJDkBeh4k0kZ-Yg_image.png "Product custom field allowed values")

- **“Reset to allow any value”** clears all allowed values with a confirmation prompt. &#x20;


![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/7FdtlqfcMyJv8YaOTDYeN_image.png)



**“Reset All License Custom Fields"&#x20;**&#x54;his action will reset all License Custom Fields for every license issued under this product.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/XwMwYxzYiS1vSnAgg2ZDI_image.png "Reset All License Custom Fields")

****


[title] Check License
[path] License API/License Check/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/check_license",
  "name": "/api/v4/check_license",
  "method": "GET",
  "request": {
    "pathParameters": [],
    "queryParameters": [
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "string",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "kind": "optional",
        "name": "license_key",
        "type": "string",
        "children": [],
        "description": "Required if product is key-based (see section below)"
      },
      {
        "kind": "optional",
        "name": "username",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "Number",
        "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "children": []
      },
      {
        "name": "include_expired_features",
        "kind": "optional",
        "type": "Boolean",
        "description": "Whether expired product features should be included in the response",
        "children": []
      },
      {
        "name": "env",
        "kind": "optional",
        "type": "String",
        "description": "Checks the licenses status against the specified product installation file environment (matching the installation file's \"environment\" property)",
        "children": []
      },
      {
        "name": "os_ver",
        "kind": "optional",
        "type": "string",
        "description": "Updates license device data, sets Operating System string to this value",
        "children": []
      },
      {
        "name": "hostname",
        "kind": "optional",
        "type": "string",
        "description": "Updates license device data, sets hostname string to this value",
        "children": []
      },
      {
        "name": "os_hostname",
        "kind": "optional",
        "type": "string",
        "description": "Legacy version of \"hostname\" parameter (see above)",
        "children": []
      },
      {
        "name": "ip",
        "kind": "optional",
        "type": "string",
        "description": "Updates license device data, sets IP address string to this value",
        "children": []
      },
      {
        "name": "ip_local",
        "kind": "optional",
        "type": "string",
        "description": "Legacy version of \"ip\" parameter (see above)",
        "children": []
      },
      {
        "name": "app_ver",
        "kind": "optional",
        "type": "string",
        "description": "Updates license device data, sets application version string to this value",
        "children": []
      },
      {
        "name": "sdk_ver",
        "kind": "optional",
        "type": "string",
        "description": "Updates license device data, sets SDK version string to this value",
        "children": []
      },
      {
        "name": "mac_address",
        "kind": "optional",
        "type": "string",
        "description": "Updates license device data, sets MAC address string to this value",
        "children": []
      }
    ],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "QLX3IFr3FPKeqNnhkuAXk",
        "code": "{\n    \"id\": 1683881344856259,\n    \"order_store_id\": \"26569ab2f28f402480c9bcbff41bb6fb\",\n    \"license_active\": true,\n    \"license_enabled\": true,\n    \"license_type\": \"perpetual\",\n    \"license_key\": \"GYLT-Z4YT-URJK-3F82\",\n    \"is_trial\": false,\n    \"validity_period\": null,\n    \"maintenance_period\": null,\n    \"allow_grace_period\": false,\n    \"grace_period\": 0,\n    \"max_activations\": 8,\n    \"allow_unlimited_activations\": false,\n    \"times_activated\": 3,\n    \"start_date\": null,\n    \"transfer_count\": 2,\n    \"max_transfers\": 0,\n    \"allow_overages\": false,\n    \"max_overages\": 0,\n    \"is_floating_cloud\": false,\n    \"is_floating\": false,\n    \"floating_timeout\": 1,\n    \"can_borrow\": true,\n    \"max_borrow_time\": 3,\n    \"prevent_vm\": false,\n    \"custom_fields\": [\n        {\n            \"name\": \"skr\",\n            \"data_type\": null,\n            \"value\": \"222\"\n        },\n        {\n            \"name\": \"1\",\n            \"data_type\": null,\n            \"value\": \"1\"\n        }\n    ],\n    \"product_features\": [\n        {\n            \"code\": \"1\",\n            \"name\": \"feature\",\n            \"feature_type\": \"consumption\",\n            \"expiry_date\": null,\n            \"metadata\": {},\n            \"max_consumption\": 2,\n            \"allow_negative_consumptions\": true,\n            \"allow_unlimited_consumptions\": false,\n            \"total_consumptions\": 0,\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"reset_consumption\": true,\n            \"consumption_period\": \"daily\"\n        },\n        {\n            \"code\": \"2\",\n            \"name\": \"feature2\",\n            \"feature_type\": \"consumption\",\n            \"expiry_date\": null,\n            \"metadata\": {},\n            \"max_consumption\": 20,\n            \"allow_negative_consumptions\": true,\n            \"allow_unlimited_consumptions\": false,\n            \"total_consumptions\": 0,\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"reset_consumption\": true,\n            \"consumption_period\": \"daily\"\n        }\n    ],\n    \"customer\": {\n        \"email\": \"teoterzic99@gmail.com\",\n        \"company_name\": \"\",\n        \"reference\": \"\",\n        \"phone\": \"\",\n        \"first_name\": \"T\",\n        \"last_name\": \"T\",\n        \"city\": \"\",\n        \"postcode\": \"\",\n        \"state\": \"\",\n        \"country\": \"\",\n        \"customer_account\": null,\n        \"metadata\": {\n            \"a\": \"b\"\n        }\n    },\n    \"product_details\": {\n        \"product_id\": 1683881296184003,\n        \"product_name\": \"p\",\n        \"short_code\": \"p\",\n        \"authorization_method\": \"license-key\",\n        \"metadata\": {}\n    },\n    \"metadata\": {},\n    \"device_id\": 1698053262137469,\n    \"is_borrowed\": false,\n    \"borrowed_until\": null,\n    \"is_expired\": false,\n    \"version\": \"\",\n    \"installation_file\": \"\",\n    \"release_date\": \"\",\n    \"hash_md5\": \"\",\n    \"requires_version\": \"\",\n    \"environment\": \"\",\n    \"eula_link\": \"\",\n    \"release_notes_link\": \"\",\n    \"size\": \"\",\n    \"channel\": \"\",\n    \"license_signature\": \"signature\"\n}",
        "language": "200",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "QLX3IFr3FPKeqNnhkuAXk"
  },
  "examples": {
    "languages": [
      {
        "id": "GWm4SySjOjdn-6ywupNB1",
        "code": "curl --location --request GET '/api/v4/check_license?hardware_id=string&product=string&license_key=string&username=string' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string'",
        "language": "curl",
        "customLabel": ""
      },
      {
        "id": "gsTpxgOWbHiB9U8ir9jcB",
        "code": "var request = require('request');\nvar options = {\n   'method': 'GET',\n   'url': '/api/v4/check_license?hardware_id=string&product=string&license_key=string&username=string',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   }\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "language": "nodejs",
        "customLabel": ""
      },
      {
        "id": "J4vOm2oUIZJ9P_rQOXMEp",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar requestOptions = {\n   method: 'GET',\n   headers: myHeaders,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/check_license?hardware_id=string&product=string&license_key=string&username=string\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "language": "javascript",
        "customLabel": ""
      },
      {
        "id": "r5vo7idj_RXGlHTFGBL2W",
        "code": "import requests\n\nurl = \"/api/v4/check_license?hardware_id=string&product=string&license_key=string&username=string\"\n\npayload={}\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"GET\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "language": "python",
        "customLabel": ""
      },
      {
        "id": "Sg-mEzK0AkT-tZRhDL5k3",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/check_license?hardware_id=string&product=string&license_key=string&username=string\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "language": "ruby",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "J4vOm2oUIZJ9P_rQOXMEp"
  },
  "description": "Checks the status and validity of license",
  "currentNewParameter": {
    "label": "Query Parameter",
    "value": "queryParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "apiv4checklicense",
  "legacyHash": "6TY_-XG04aw-vgfUVo06E"
}
```
:::

## Schema

### Request Query Parameters

:::CodeblockTabs
```typescript
type LicenseCheckQueryParameters = ({

  // for key-based licenses:
  license_key: string

} | {

  // for user-based licenses:
  username: string

}) & {

  // required properties:
  hardware_id: string
  product: string

  // optional properties:
  license_id?: number | undefined
  is_vm?: boolean | undefined
  vm_info?: string | undefined
  os_ver?: string | undefined
  hostname?: string | undefined
  os_hostname?: string | undefined
  ip?: string | undefined
  ip_local?: string | undefined
  app_ver?: string | undefined
  sdk_ver?: string | undefined
  mac_address?: string | undefined
  include_expired_features?: boolean | undefined
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "allOf": [
    {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "license_key": { "type": "string" }
          },
          "required": ["license_key"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "username": { "type": "string" }
          },
          "required": ["username"],
          "additionalProperties": false
        }
      ]
    },
    {
      "type": "object",
      "properties": {
        "hardware_id": { "type": "string" },
        "product": { "type": "string" },
        "license_id": { "type": "number" },
        "is_vm": { "type": "boolean" },
        "vm_info": { "type": "string" },
        "os_ver": { "type": "string" },
        "hostname": { "type": "string" },
        "os_hostname": { "type": "string" },
        "ip": { "type": "string" },
        "ip_local": { "type": "string" },
        "app_ver": { "type": "string" },
        "sdk_ver": { "type": "string" },
        "mac_address": { "type": "string" },
        "include_expired_features": { "type": "boolean" },
      },
      "required": ["hardware_id", "product"],
      "additionalProperties": false
    }
  ]
}
```
:::

### Response Body

:::CodeblockTabs
```typescript
type LicenseCheckResponseBody = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  borrowed_until: string | null,
  can_borrow: boolean,
  channel: string,
  device_id: number,
  enable_maintenance_period: boolean
  environment: string,
  eula_link: string,
  floating_timeout: number,
  grace_period: number,
  hash_md5: string,
  installation_file: string,
  is_air_gapped: boolean,
  is_borrowed: boolean,
  is_expired: boolean,
  is_floating_cloud: boolean,
  is_floating: boolean,
  is_hardware_key_auth: boolean,
  license_active: boolean,
  license_enabled: boolean,
  license_signature: string,
  license_signature_v2: string,
  offline_signature: string,
  license_type: string,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users: number,
  max_overages: number,
  max_transfers: number,
  order_store_id: string,
  prevent_vm: boolean,
  release_date: string,
  release_notes_link: string,
  requires_version: string,
  size: string,
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null, // string is in DateISO8601UTC format
  version: string,
  company: { id: number },
  
  product_features: ({
    id: number,
    code: string,
    name: string,
    expiry_date: string,
    metadata: JSON,
    feature_type: 'activation' | 'consumption',
    is_floating: boolean,
    is_floating_cloud: boolean,

    // the following properties are only present if is_floating=true or is_floating_cloud=true
    floating_users: number,
    floating_timeout: number,

    // the following properties are only present if feature_type=consumption
    max_consumption: number,
    allow_unlimited_consumptions: boolean,
    total_consumptions: number,
    allow_overages: number,
    max_overages: number,
    reset_consumption: boolean,
    consumption_period: 'daily' | 'weekly' | 'monthly' | 'annualy' | null,
    can_borrow: boolean,
    max_borrow_time: number,
  })[],
  
  custom_fields: ({
    name: string,
    data_type: 'numer' | 'text' | 'date/time',
    value: string,
  })[],
  
  customer: {
    email: string,
    company_name: string,
    reference: string,
    phone: string,
    first_name: string,
    last_name: string,
    city: string,
    postcode: string,
    state: string,
    country: string,
    address: string,
    customer_account: string | null,
    metadata: JSON,
  },
  
  product_details: {
    product_id: number,
    product_name: string,
    short_code: string,
    authorization_method: 'license-key' | 'user',
    metadata: JSON,
  },
  
  metadata: JSON,
  
  // the following property is only present if is_trial=true
  trial_days: number,
  
  // the following properties is only present if is_floating=true or is_floating_cloud=true
  floating_in_use_devices: number,
  floating_users: number,
  
  // the following properties are only present if license_type='consumption'
  max_consumptions: number,
  total_consumptions: number,
  allow_unlimited_consumptions: boolean,
  reset_consumption: boolean,
  consumption_period: string | null, // string is in DateISO8601UTC format
  
} & ({

  // for key-based licenses:
  license_key: string,

} | {

  // for user-based licenses:
  user: {
    id: number,
    email: string,
    first_name: string,
    last_name: string,
    phone_number: string,
    is_initial_password: boolean,
    max_activations: number,
    allow_unlimited_activations: boolean,
    total_activations: number
  }
});

```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "oneOf": [
    {
      "type": "object",
      "properties": {
        "license_key": { "type": "string" }
      },
      "required": ["license_key"]
    },
    {
      "type": "object",
      "properties": {
        "user": {
          "type": "object",
          "properties": {
            "id": { "type": "number" },
            "email": { "type": "string" },
            "first_name": { "type": "string" },
            "last_name": { "type": "string" },
            "phone_number": { "type": "string" },
            "is_initial_password": { "type": "boolean" },
            "max_activations": { "type": "number" },
            "allow_unlimited_activations": { "type": "boolean" },
            "total_activations": { "type": "number" }
          },
          "required": ["id", "email", "first_name", "last_name", "phone_number", "is_initial_password", "max_activations", "allow_unlimited_activations", "total_activations"]
        }
      },
      "required": ["user"]
    }
    ],
  "properties": {
    "id": { "type": "number" },
    "allow_grace_period": { "type": "boolean" },
    "allow_overages": { "type": "boolean" },
    "allow_unlimited_activations": { "type": "boolean" },
    "borrowed_until": { "type": ["string", "null"] },
    "can_borrow": { "type": "boolean" },
    "channel": { "type": "string" },
    "device_id": { "type": "number" },
    "enable_maintenance_period": { "type": "boolean" },
    "environment": { "type": "string" },
    "eula_link": { "type": "string" },
    "floating_timeout": { "type": "number" },
    "grace_period": { "type": "number" },
    "hash_md5": { "type": "string" },
    "installation_file": { "type": "string" },
    "is_air_gapped": { "type": "boolean" },
    "is_borrowed": { "type": "boolean" },
    "is_expired": { "type": "boolean" },
    "is_floating_cloud": { "type": "boolean" },
    "is_floating": { "type": "boolean" },
    "is_hardware_key_auth": { "type": "boolean" },
    "license_active": { "type": "boolean" },
    "license_enabled": { "type": "boolean" },
    "license_signature": { "type": "string" },
    "license_signature_v2": { "type": "string" },
    "offline_signature": { "type": "string" },
    "license_type": { "type": "string" },
    "maintenance_period": { "type": ["string", "null"] },
    "max_activations": { "type": "number" },
    "max_borrow_time": { "type": "number" },
    "max_license_users": { "type": "number" },
    "max_overages": { "type": "number" },
    "max_transfers": { "type": "number" },
    "order_store_id": { "type": "string" },
    "prevent_vm": { "type": "boolean" },
    "release_date": { "type": "string" },
    "release_notes_link": { "type": "string" },
    "requires_version": { "type": "string" },
    "size": { "type": "string" },
    "start_date": { "type": ["string", "null"] },
    "times_activated": { "type": "number" },
    "transfer_count": { "type": "number" },
    "validity_period": { "type": ["string", "null"] },
    "version": { "type": "string" },
    "company": { "type": "object", "properties": {"id": { "type": "number" } } },
    "product_features": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": { "type": "number" },
          "code": { "type": "string" },
          "name": { "type": "string" },
          "expiry_date": { "type": ["string", "null"] },
          "metadata": {},
          "feature_type": { "type": "string", "enum": ["activation", "consumption"] },
          "is_floating": { "type": "boolean" },
          "is_floating_cloud": { "type": "boolean" },
          "floating_users": { "type": "number" },
          "floating_timeout": { "type": "number" },
          "max_consumption": { "type": "number" },
          "allow_unlimited_consumptions": { "type": "boolean" },
          "total_consumptions": { "type": "number" },
          "allow_overages": { "type": "boolean" },
          "max_overages": { "type": "number" },
          "max_borrow_time": { "type": "number" },
          "can_borrow": { "type": "boolean" },
          "reset_consumption": { "type": "boolean" },
          "consumption_period": {
            "type": ["string", "null"],
            "enum": ["daily", "weekly", "monthly", "annualy", null]
          }
        },
        "required": ["code", "name", "expiry_date", "metadata", "feature_type"]
      }
    },
    "custom_fields": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "data_type": { "type": ["string", "null"], "enum": ["numer", "text", "date/time", null] },
          "value": { "type": "string" }
        },
        "required": ["name", "data_type", "value"]
      }
    },
    "customer": {
      "type": "object",
      "properties": {
        "email": { "type": "string" },
        "company_name": { "type": "string" },
        "reference": { "type": "string" },
        "phone": { "type": "string" },
        "first_name": { "type": "string" },
        "last_name": { "type": "string" },
        "city": { "type": "string" },
        "postcode": { "type": "string" },
        "state": { "type": "string" },
        "country": { "type": "string" },
        "address": { "type": "string" },
        "customer_account": { "type": ["string", "null"] },
        "metadata": {}
      },
      "required": ["email", "company_name", "reference", "phone", "first_name", "last_name", "city", "postcode", "state", "country", "metadata"]
    },
    "product_details": {
      "type": "object",
      "properties": {
        "product_id": { "type": "number" },
        "product_name": { "type": "string" },
        "short_code": { "type": "string" },
        "authorization_method": { "type": "string", "enum": ["license-key", "user"] },
        "metadata": {}
      },
      "required": ["product_id", "product_name", "short_code", "authorization_method", "metadata"]
    },
    "metadata": {},
    "trial_days": { "type": "number" },
    "floating_in_use_devices": { "type": "number" },
    "floating_users": { "type": "number" },
    "max_consumptions": { "type": "number" },
    "total_consumptions": { "type": "number" },
    "allow_unlimited_consumptions": { "type": "boolean" },
    "reset_consumption": { "type": "boolean" },
    "consumption_period": { "type": ["string", "null"] }
  },
  "required": [
    "id",
    "allow_grace_period",
    "allow_overages",
    "allow_unlimited_activations",
    "can_borrow",
    "channel",
    "device_id",
    "environment",
    "eula_link",
    "floating_timeout",
    "grace_period",
    "hash_md5",
    "installation_file",
    "is_borrowed",
    "is_expired",
    "is_floating_cloud",
    "is_floating",
    "license_active",
    "license_enabled",
    "license_signature",
    "license_type",
    "max_activations",
    "max_borrow_time",
    "max_overages",
    "max_transfers",
    "order_store_id",
    "prevent_vm",
    "release_date",
    "release_notes_link",
    "requires_version",
    "size",
    "times_activated",
    "transfer_count",
    "version",
    "product_features",
    "custom_fields",
    "customer",
    "product_details",
    "metadata"
  ] 
}
```
:::

### Response Signatures

The response objects contains the following digital signature:

- &#x20;`license_signature`: see the [**Response Signature**](docId\:ouciGcAGCAIKAdWCbx9Wk) article
- `license_signature_v2`: see the [**Response Signature v2**](docId\:VOa8G6UH1hS_qoq34lb8S) article
- `offline_signature`: can be used for activating/deactivating using the offline method, see the [**Deactivate License (Offline Method)**](docId\:iyg1DXIYqp9vW-Mlj-xUk)  article

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

### Key-based product licenses

Each license assigned to the product requires the client to provide a license key in order to activate, check or deactivate the license (property `license_key` in the request body).

The license response object will contain the `license_key` property, and the property `product_details.authorization_method` will be the string `license_key`.

### User-based product licenses

Each license assigned to the product has a corresponding "license user" instead of a license key. Requires `username` and to be provided.

In the license response object, `product_details.authorization_method` will have the string value `user` and the response object will contain the `user` object with information on the license user.&#x20;

## License Types

The `license_type` property defines one of the 4 types of licenses based on their duration and how the license is used:

- Perpetual: `perpetual`
- Time-limited: `time-limited`
- Subscription: `subscription`
- Consumption: `consumption`

For more information see: [**License Types**](docId\:xHxttCVj7gs6qeAqu7Cua)&#x20;

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**missing\_headers** (400): Some headers are missing
:::

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**license\_not\_found** (400): License with the provided license user not found
:::

:::BlockQuote
**license\_not\_enabled** (400): The license is not enabled
:::

:::BlockQuote
**license\_not\_active** (400): The license is not active
:::

:::BlockQuote
**device\_not\_found** (400): An active device matching the hardware\_id not found
:::

:::BlockQuote
**blacklisted** (400): This device is blacklisted
:::

:::BlockQuote
**license\_not\_enough\_consumptions** (400): Not enough consumptions left
:::

:::BlockQuote
**floating\_not\_available** (400): No available slots for floating license
:::

:::BlockQuote
**product\_version\_not\_supported&#x20;**(400): License product version does not support the app\_ver sent in the request
:::


[title] Floating Features
[path] License Entitlements/

## Floating Product Feature Setup

Before creating a floating product feature, it is essential to set up the product [**here**](https://docs.licensespring.com/getting-started/creating-and-configuring-products).

To create floating feature go to **Product** -> **Features** -> **Add product feature** \[button]



![Create floating feature](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/F-VZbcMixoUwfgdkhqPIE_scr-20231025-mtdc.png "Create floating feature")

- Check `Is floating cloud` checkbox
- Enter default value for `Max simultaneous feature users` ( In datamodel this is `floating_users` field determines  how many users can use feature simultaneously)
- Enter default value for `Floating timeout` ( after how many minutes of inactivity will the license feature device be released

:::hint{type="info"}
`Max simultaneous feature users`*and&#x20;*`Floating timeout`fields are default values fo&#x72;*&#x20;Product features* and they can be overwritten when creating *License product feature&#x20;*
:::

## Create License Product Feature

License product feature is created when issuing a license and attaching a feature to it.

This can be done programatically when creating order or edit license features using [**Management API**](https://docs.licensespring.com/management-api/product/features/create) or from inside the plaform on **Issue licenses&#x20;**&#x76;iew inside **Product features** \[tab]. Floating features will have an orange colored label `floating`

Here you can also overwrite default values for `Max simultaneous license users` and `Floating timeout`

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/qi0wvbpb6aFGuXUhF3rs3_image.png "Create License product feature")

## License Features View

To see the License product features details go to the **License&#x20;**-> **Product features** \[tab].

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/QDX_lZCVJCAxyPbAZfY7T_image.png)

If a license feature is a floating feature, under **Floating slots** column you should see information how many floating slots are available and how many are used in a form of `used_slots/max_slots` ( eq. 1/5 one used slot of five available). Additional floating feature informations can be observed when expanding the row by clicking on a `Details` icon on that row. Fields displayed there will be:

- `Is floating cloud`
- `Max simultaneous users`
- `Floating timeout`

**Devices** column will display all the devices which were used to check the specific feature using the new License API endpoint `/api/v4/check_license_feature`.&#x20;

:::hint{type="info"}
Any license device can check any license feature, it does not have to be a floating feature. That way we can also display a clear connection between license devices and features which they use.  It is not required for **non-floating** features.
:::

Click on a Devices cell for some feature will open **License feature devices pop-up** with a list of all feature devices.&#x20;



![License feature devices popup](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/yH_5x1CKmIGLEIRi1wfkc_scr-20231026-koan.png "License feature devices popup")

Floating feature devices will have additonal columns:

- `In use` - Boolean representing if this devices is using a floating feature slot
- `Revoke` - Action button which opens a confirmation window. On confirm that device will be released and the floating slot will be opened for another device. Only devices which are in use can be revoked using the UI.

![Confirmation popup](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/gfoyK1B9V54IaGfEpFK40_scr-20231026-kobs.png "Confirmation popup")

:::hint{type="warning"}
Borrowing for license floating features is not implement at the moment.&#x20;
:::


[title] Roles/Permissions/User Labels
[path] Vendor Platform/Settings/

You can set custom permissions for platform users.

:::hint{type="info"}
Admin users have all permissions by default.
:::

The Options available are:

- `Product` Read/Manage/None
- `Orders` Read/Manage/None
- `Licenses` Read/Manage/None
- `Customers` Read/Manage/None
- `Analytics` Read/None
- `Settings` Read/Manage/None
- `Billing` Read/Manage/None
- `Platform users` Read/Manage/None

:::hint{type="info"}
* **Read access** to Settings allows a user to **view API keys**.
* **Write access** to Settings allows a user to **create webhooks**.
:::

## Creating a Permissions Template

Creating a permissions template allows you to easily set permissions for a new or existing user or group of users.

To create a new permissions template:

- Navigate to "Settings" > "Permissions"
- Click "Add new permissions template"

![Add New Permissions Template Button](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/yGCHUh5JLLgDzLyyZu_4C_image.png "Add New Permissions Template Button")

Give your new permissions template a name and set the access level you wish to grant to any user that you apply this template to, then click confirm when you're done:

![Setting New Permissions](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/HWmkyjT2C4LQzDpVGBNhw_image.png "Setting New Permissions")

:::hint{type="warning"}
Modifying a permissions template will not affect permissions of any given user.
:::

## Setting Permissions for a New User

When adding a new user to the vendor platform, you can either assign them "Admin" privileges, or you can set permissions from any template already created in the account.

You can add a new platform user by navigating to "Settings" > "Users" > "Add new User".

![Add New Platform Users](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/6bPOGZu8etTtWHBb02TyF_image.png "Add New Platform Users")

You will have the options to set permissions on the popup.

![Setting User Permissions](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/_s551rVuzbkrWShXJt8YF_image.png "Setting User Permissions")

## Applying Permissions to an Existing Platform User

### For an Individual Platform User

Navigate to the platform user detail view. From this screen, you can:

- Toggle whether this user is an administrator for the account
- Edit individual permission settings (if they are not admin)
- Apply permissions from an existing template (if they are not admin

![Editing Permissions for Existing User](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Jp1_ym9gn21ic1BYZ5Xxz_image.png "Editing Permissions for Existing User")

### Apply Permissions Template to a Group of Platform Users

You can apply a permissions template all platform users that have a certain label.

![Assign Permissions Temlate to User Label](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/4l8CpbGFl-luxHttJbTm1_image.png "Assign Permissions Temlate to User Label")


[title] Add New Account
[path] Vendor Platform/Customer Accounts/

This page is used to add a new customer account to the system.

![Add Cusomer View](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/TRNrG8p3Rgxnm2oaDekbv_image.png)

&#x20;The form is divided into two columns and includes the following fields:

### Customer Information Fields

- **Name:** Enter the full name of the customer.
- **Code:** Enter a unique code for the customer (e.g., "QQ").
- **Email:** Enter the customer's email address.
- **Reference:** Add any internal reference or identifier for the customer.

### Additional Details

- **Address:** Enter the customer's address.
- **Phone Number:** Enter the customer's phone number, including the country code.
- **Description:** Add any additional notes or description about the customer.
- **Metadata JSON:** (Optional) Enter any extra metadata in JSON format for advanced use cases or integrations.


[title] Users
[path] Vendor Platform/Settings/

## Has Accepted Invitation

"Has accepted invitation" refers to the status of a user who has successfully responded to and confirmed their invitation to join an account. When a user is added to the account, they receive an email invitation that includes a link to activate their account.&#x20;

If the user clicks on the activation link within the given time limit, they are considered to have accepted the invitation. As a visual indicator, a green checkmark is typically displayed to signify that the user has successfully accepted and confirmed their invitation.

However, if the user fails to accept the invite within the specified timeframe, the invitation expires. In such cases, a new invitation needs to be sent to the user for them to join the account. This time limit is in place to protect the security of the account and ensure that only authorized individuals gain access.

## User Password-Setup

Typically, initial passwords are system-generated and can be a weak link in security if not promptly updated

### a) API&#x20;

To manage this, users should  inspect the "is\_initial\_password" field. To acess field "is\_initial\_password" you can ouse this endpoint --> [**https://docs.licensespring.com/management-api/license/users/retrieve**](https://docs.licensespring.com/management-api/license/users/retrieve). Value of True indicates that the initial password of user is still in use. At this juncture, it is advisable to prompt users with an  interface that encourages them to change password of their own choice. You can do this with enpoints --> [**https://docs.licensespring.com/management-api/license/users/set-password**](https://docs.licensespring.com/management-api/license/users/set-password) and [**https://docs.licensespring.com/management-api/license/users/set-password-by-email**](https://docs.licensespring.com/management-api/license/users/set-password-by-email).

### b) User-Interface

First you can check if user has initial password inside platform([**https://saas.licensespring.com/**](https://saas-staging.licensespring.com/)).&#x20;

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/FfJ3CGUqh4xkDm-Z4Xy2r_image.png "Initial password check")

Conversely, a **N/A** value in this field signifies that the  initial password has already been replaced by the user.&#x20;

For user to change password user should go inside to [**https://users.licensespring.com/**](https://users-staging.licensespring.com/). He should login in with initial password. After that he should go to MyProfile --> Change Password

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/lnX4xFMCvbnCvoiwUDCSI_image.png "User password change")

&#x20;


[title] Orders Export
[path] Vendor Platform/Importing/Exporting Data/

The export orders functionality allows you to extract detailed order data in CSV format for reporting, auditing, or analysis. You can export orders through the platform interface or programmatically using the Management API.

## Exporting Orders via Platform Interface&#x20;

### **1. Navigate to the Orders Section**

- Open the `Orders` menu from the sidebar and select `All Orders`, as shown below:

![All Orders Tab](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/656sKK48wbnAXGIkBO4kJ_image.png "All Orders Tab")

### **2. Apply Filters (Optional)**

- Use the `Search Filters` option to narrow down the licenses to be exported.
- Available filters include:
  - **Customer Labels**: Filter licenses by associated customer labels.\\

![Search filters button](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/XCYY7OD3ZuXn7RYxka8nr_image.png "Search filters button")

### **3. Initiate the Export**

- Click the `Export Orders` button located in the top-right corner of the orders page.

![Export Orders Button](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/CLTnPrYL4DxbakV7huWgC_image.png "Export Orders Button")

### **4. Set Export Options**

- In the `Export Orders` pop-up:
  - Choose a **date range** for the licenses you want to export.
  - Review and confirm any applied filters.
  - Clear filters directly in this dialog if necessary.

![Export Orders Pop-up](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/oxAxH16_ke0qpvhPuB7Dw_image.png "Export Orders Pop-up")

### **5. Confirm and Export**

- Click the `Confirm` button to start the export process.
- The platform will generate a CSV file containing the license data that matches your filters.

## Exporting Orders via Management API&#x20;

### Exporting a Single Order&#x20;

If you need to export a single order programmatically, the Management API provides an endpoint for this purpose.&#x20;

For more information on how to use this endpoint, see our page at [**Export Order**](docId\:QaxJKqeXhyOwrZJczMgUb).

### Exporting Multiple Orders via Management API

The API also allows for exporting multiple orders in bulk.

For more information on exporting multiple orders, see [**Export Orders**](docId\:Z2st14HvK5YjrLN0rkDtk).


[title] Online License Activation
[path] License Entitlements/License Activation Types/

:::hint{type="info"}
Online license activations are done via the license API, and can be initialized through one of the SDKs that we maintain. For more information on license activation via one of the SDKs or via the license API, please review their respective articles in this documentation.
:::

## General Process

- A license must first be issued, and dispatched to the end user.
- The end-user will enter the license authorization mechanism (usually a license key or an email/password, but we also support activating licenses using single sign on) into their software application
- The Software will attempt to communicate with the LicenseSpring server. If this license is authorized and valid, the server will return the License information.

## Required Fields to Make a Valid Activation Request

Generally speaking, the client application will need to send at a minimum the following information to the LicenseSpring server in order to activate a license:

- `hardware_id`: unique device, session, or environment identifier, usually computed by the SDK.
- `product_code`: This is a field that is set when initializing the product
- license authorization: Either a license key, or user credentials, depending on the authorization set on the product.




[title] API Key Authorization
[path] License API/License API Authorization/

## Overview

To ensure the integrity of server requests, every request must be **signed**. The **signature** serves as a unique representation of the request and is included in the **Authorization** header.

### Signature Details

The signature is generated using a specific algorithm applied to the request parameters. The resulting value is a canonicalized signing string, ensuring the request's authenticity.

### Required Headers

Each client request must include the following headers:

::::WorkflowBlock
:::WorkflowBlockItem
**Date**

Current time given as a date string in [**RFC7231**](https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.1.1) format. Note that this value is always in the GMT timezone.

Example: `Date: Tue, 07 Jun 2014 20:51:35 GMT`
:::

:::WorkflowBlockItem
**Authorization**

This header contains information on how the request is authorized:

- **algorithm**: Defines the signature hashing algorithm, by default `hmac-sha256`
- **headers**: Defines the headers used to derive the signature, set this to `date`
- **apikey**: The API key used for the request
- **signature**: The Base64-encoded value of the signing string. See the specification is on the [**Request Signature**](docId\:kM0ibIPcI1fqUcLtts9sJ) page.

Example Authorization header:

```none
algorithm="hmac-sha256", headers="date", signature="_base64_here_", apikey="_company_api_key_here_"
```


:::
::::

:::hint{type="warning"}
Ensure that the Date header value is set to current time. The server allows timestamps that are up to 15 minutes old.
:::

## Errors

All returned errors have an HTTP status code of 400 or higher, and a response body as follows:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

The following is list of errors related to Authorization are common for all License API endpoints:

:::BlockQuote
**date\_header\_diff** (400)
:::

:::BlockQuote
**authorization\_invalid\_headers** (400)
:::

:::BlockQuote
**hmac\_required** (400)
:::

:::BlockQuote
**signature\_mismatch** (400)
:::

:::BlockQuote
**authorization\_missing\_params** (400)
:::

:::BlockQuote
**invalid\_api\_key** (400)
:::

:::BlockQuote
**revoked\_api\_key** (400)
:::

:::BlockQuote
**read\_only\_api\_key** (400)
:::




[title] Global Features
[path] Product Configuration/Untitled/

## **Global Feature**

In LicenseSpring, a **Global Feature** is an attribute that is not tied to any specific product, and can be added to licenses issued for any product. Global features provide flexibility when you need to define attributes that apply across multiple products rather than being limited to a single one.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/GiB42Hig6iYqScXTIKcm-_screenshot-10-31-2025-153928.png)

## Activation Global Feature

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/dSW8siIfSvSHISCBjKsbD_image.png)

Activation Features are used to enable or disable specific functionality within a licensed product, such as a component, module, or set of features.

Once defined, an Activation Feature can be added to or removed from a license as needed. It does not include additional attributes beyond its activation state.

## Consumption Global Feature

Consumption Features are used to meter the usage of a component or resource, such as an API, the number of times a report is generated, or the amount of time (in seconds or minutes) that a resource is used.

Consumption Features, like Activation Features, can be added to or removed from a license. However, Consumption Features also include the attributes Max Consumption, Allow Overages (Boolean), Max Overages value, and an option to reset consumption allowances periodically.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/pQNNzHpMEoKYvdNX74r8I_image.png)

## Time limited Global features

Optionally you can define an expiration for the features. You can either set expiration to a specific date ( `Expiry date` ) or you can set a Valid duration to a feature which is then used to calculate a specific expiry date at the time of the first license activation.

Features that do not have expiry\_date defined, are never expired.

License API will also return `is_expired` Bool for every feature. To include expired features to a license check and license activation response, use[**&#x20;include\_expired\_features**](https://docs.licensespring.com/license-api/check) parameter.

Feature expiration policy can be defined on a global feature, product features, license feature and license policy level.

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/dHYATNeN6fNt9HCVUP02-_image.png "Set Expiration")

## Define a New Global Feature

### Required Fields

- Feature Name
- Feature Code
- Feature Type

### Fields for Consumption Global Features

- Max Consumptions
  - Allow Unlimited Activations
- Allow Overages
  - Max Overages
- Reset Consumption
  - Consumption Period

To add a new **Global Feature**, use the left sidebar, click on **Products,** and then select **Global Features.**

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/m84JLZxAU32gbS_yAW0qG_image.png "Adding a Global Feature")

Give the Feature a Name, a Code, and select its type.

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/ynt0WLBF0xv5SB40gYR1V_image.png "Global Feature Form")

If the feature is of type consumption, set the default value for Max Consumption, the Value for Max Overages, as well the time interval for which the allowances should reset

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/2CUkN4dVEfNg4HeCsm610_image.png "Global Feature Configuration")

## Editing/Deleting Global Features

:::hint{type="info"}
You can rename a global feature, and the default values for consumption features can be modified. However, you cannot change a global  feature code.
:::

:::hint{type="danger"}
If you delete a **Global Feature**, it can be removed from licenses, but you can **add it back to any license at any time**. Unlike Product Features, Global Features are not permanently tied to licenses, so there is no restriction on re-adding them.
:::

- To edit a global feature, go to the features list and click on the Pencil icon on the row for that global feature.
- To delete a global feature, click on the red garbage can icon on the row for that global feature.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/euTcNnbAVyBAMeMxgkzkn_image.png)

## Global Feature groups

Features can be organized into feature groups to simplify license management.When creating a license, instead of adding each feature individually, a group code can be attached, and all features within that group will be included automatically.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/U7MmPJAlWfj4b4UGMt-Fj_image.png)

Groups behave similar to license policies in a way that you can also define time limited settings on a group level that would be applied to all license features when license is created.

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/SfR8WOXazwoAQlTmY_G5e_image.png "Selecting Group Features During Order Creation")

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/a4rNISRChqZPfAdAe0vC8_image.png "Adding Global Feature Group Form")

Feature groups can be applied to a license policy or used directly when creating order.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/FOEXG99t7728F1bT7fe8m_image.png)


[title] Issuing New Licenses
[path] Vendor Platform/Licenses/

There are a few ways you can issue licenses:

- Manually through the Vendor platform
- Through the Management API
- With one of our integrations

## Our Data Model

Before issuing a license, it might help to know how our data model is organized:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ZVO3W0XsnxSGeeYOmOalS_image.png)

- **A License&#x20;**&#x63;an belong to an order. You can have 0 to many licenses for an order
- **An Order&#x20;**&#x63;an belong to a customer. You can have 0-to-many orders for a customer
- **A Customer&#x20;**&#x63;an belong to an account. You can have 0-to-many customers for an account.

:::hint{type="info"}
A License will belong to an order. If you do not specify an orderID, a random orderID will be generated
:::

Orders do not need to belong to customers. However, it can be useful to have this association for analytics, or for customer support, for example.

## Issuing New Licenses Manually Through the Vendor Platform

:::hint{type="info"}
We are assuming you have already created a product within your vendor account.
:::

To issue a new license for your product, click on the "Licenses" tab on the left, and then click on "create new order on the right of the screen:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/qtMZLPe4AJhoj19cSc-lB_image.png)

The next screen allows you to add order identifiers and customer information, if you want to, but it's optional. Click Next:&#x20;

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8FlZGHympDS5f01ty0hvc_image.png)

The next screen allows you to configure the licenses you wish to issue. Click "Add Product", and a configuration screen allows you to configure the entitlements that you will be adding to the license.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/osHBsrhQJegQTpyvCIIhc_image.png)

Select the product you want to issue licenses for, and then configure the licenses you wish to issue. You can select a license policy if you have created any when configuring the product. Otherwise, select "use custom values" and it will allow you to fully customize the license entitlements that will go on it.

You can specify many different options such as:

- The license type: Perpetual, Time-limited, Subscription, or Consumption-based
- Which features should be added to a license
- How many devices can node lock to a license with the "max activations" field
- unique values for the license custom fields
- etc.&#x20;

When you are done configuring the license entitlements, click "Confirm".

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/boISCOt-s_Ob0z4G4NPdl_image.png)

Review your license configuration on the "Confirm Order" screen, and press "Create order" when you are done. The Order detail page will appear on the next screen where you can retrieve your new licenses.



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/rDqkaV38WMzBTmNnUdcuv_image.png "Creating Order")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Yk-Ln6oSjqbKLqwM5dRXX_image.png)


[title] Comparison of Floating Cloud and Floating Server Licenses
[path] License Entitlements/Floating Licenses/

## **Activation & Registration**

- **Floating Cloud**: Activation is managed via LicenseSpring’s cloud platform, meaning the client communicates with the cloud for license issuance and revocation. This requires internet access. In contrast to a floating server setup, a floating cloud license demands individual activation on every device aiming to utilize the license since the license is bound to the client device. An in-depth guide for activating on the floating cloud can be found on our [**Floating Cloud Guide**](https://docs.licensespring.com/sdks/tutorials/licensing-scenarios/floating?_gl=1*gipckn*_up*MQ..*_ga*MTU1MDk4NjMwOC4xNzI5MjY4NDU3*_ga_WP8X5PQ7N7*MTcyOTI2ODQ1Ni4xLjAuMTcyOTI2ODQ1Ni4wLjAuMA..#SpuTq) 
  - With a floating cloud license, you must first activate any client that will be allowed to register a license.
- **Floating Server**: License activation happens locally, on-premise, using a self-hosted floating server. Internet connection is not required for clients to check in/out licenses since all interactions between the floating server and client application happen over the local network. The license is bound to the floating server for floating server licenses. Licenses can be activated online, offline, air-gapped or by using a hardware key on the floating server with guides for each being found in our [**Floating Server Registration Documentation**](https://docs.licensespring.com/license-options)**.**
  - With a floating server, you first activate the floating server, then any clients on the private network may register to it.

## **Online/Offline Access**

- **Floating Cloud**: Requires constant internet access to check out licenses and perform license checks.
- **Floating Server**: Clients can operate completely offline as long as they can communicate with the on-premise server. Internet connection is required only for online licenses check outs and syncs. The floating server can handle offline floating features, allowing operations in air-gapped or restricted environments. Offline licensing on the floating server can be done by following the steps in our [**Offline Activation Documentation**](https://docs.licensespring.com/offline). 

## **Floating Features**

- **Floating Cloud**: Provides concurrent licensing features, allowing users to check in/out licenses dynamically, with cloud-based management of license usage.
- **Floating Server**: Supports similar features but locally, including offline floating features that allow the licenses to be borrowed or used without an active internet connection. More information about floating features on the floating server can be found in our [**Floating Server Floating Features Documentation**](https://docs.licensespring.com/fcSU-floating-features). 

More general information about how to use floating features in your code can be found at [**Floating Features Documentation**](https://docs.licensespring.com/sdks/tutorials/licensing-scenarios/floating-features).

## **License Borrowing**

- **Floating Cloud**: Users can borrow licenses for a specified time, allowing them to work offline. This feature still requires an internet connection for the initial borrowing process. A license can be borrowed over the floating cloud with [**License Borrow**](https://docs.licensespring.com/license-api/floating/license/borrow). 
- **Floating Server**: Offers more flexibility with offline environments, allowing licenses to be borrowed without any internet connection, as long as the borrowing happens locally on the server. A license can be borrowed on the floating server with [**Floating Server License Borrow**](https://docs.licensespring.com/floating-server/api/registration/borrow)**.**

## **Hardware Keys**

- **Floating Cloud**: Not typically used for cloud licenses.
- **Floating Server**: Hardware keys can be used to secure the floating server setup, preventing unauthorized copying or misuse of the server installation. More information at [**Floating Server Hardware Keys**](https://docs.licensespring.com/floating-server/hardware-keys).

## **Setting Up the SDK**

- **Floating Cloud**: Easier setup as there is no need for local server configuration; the client SDK interacts directly with the cloud.
- **Floating Server**: More involved, requiring setup and configuration of the local server path and network settings. More information at [**Floating Server Setup**](https://docs.licensespring.com/floating-server).

## **Analytics and Reporting**

- **Floating Cloud**: Reports can be generated via the LicenseSpring platform, providing real-time insights into license usage and status.
- **Floating Server**: The floating server's reporting capabilities are currently limited compared to the cloud reporting. At present, floating usage and consumption data are stored locally on the server. When an internet connection is available, this data is sent to the cloud, from where it is later used to generate reporting graphs. However, if the server is offline, only CSV reports are available, with no graphical reports.

For other metrics, such as API calls and activation/deactivation events, users must rely on cloud-based analytics and reporting. This setup is expected to change in version 2, where the goal is to align the floating server's reporting capabilities more closely with those of the cloud. For now, though, the reporting remains as described.

General information about analytics and reporting at LicenseSpring can be found within our [**Analytics Documentation**](https://docs.licensespring.com/vendor-platform/analytics).

## **User Portal and License Manager Permissions**

- **Floating Cloud**: Permissions for users and administrators can be managed via LicenseSpring’s web portal, providing easy access to manage licenses remotely. 
- **Floating Server**: User management is handled locally, but roles and permissions can be customized in a similar way. However, some advanced cloud-based features (like real-time updates) might be limited.

Find information about our end-user portal in our [**End-User Portal Documentation**](https://docs.licensespring.com/portals/end-user).

## **Consumption Syncing/Caching Mechanisms**

- **Floating Cloud**: Data on license consumption is locally cached, it is necessary to sync consumptions (just like with non-floating licenses) to accurately reflect consumption data on the LicenseSpring platform.
- **Floating Server**: Consumption data is tracked locally, and syncing with LicenseSpring’s platform (if necessary) is performed via periodic updates every hour. This syncing does not occur when running in offline mode.


[title] License Managers
[path] Vendor Platform/

**License Managers**: This is a user role responsible for managing licenses for a group or organization. They have access to the [**end-user portal**](https://app.archbee.com/docs/FbT_Z5Cu33D-LVZx1fRkU/BOD5TlwkFFKiKasV1ZsrY), where they can perform actions based on the **permissions that have been enabled** for them.&#x20;

This view gives you an overview over license managers you have created for your account.&#x20;

![License Managers View](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/WwV0DVHu1R3Enz1de3QR1_image.png "License Managers View")

You can setup a default permission set for any license manager created in the future and you can inspect license manager details ( eq. his permission set, orders, licenses, user groups and some reporting ).

- **License Manager Guide**
  A comprehensive walkthrough of the end-user portal. It covers all key roles, core concepts, and actions, including managing licenses, devices, orders, users, and more. You'll also find sections on permissions, floating licenses, API integrations, and detailed workflows. [**https://docs.licensespring.com/portals/user-portal/guide**](https://docs.licensespring.com/portals/user-portal/guide)
- **The License Manager**
  This page details the role of a License Manager within the platform. It explains how to assign a user as a License Manager, the permissions they can have (such as issuing licenses, managing users, and resetting devices), and how to add them to existing orders. [**https://docs.licensespring.com/portals/user-portal/the-license-manager**](https://docs.licensespring.com/portals/user-portal/the-license-manager)


[title] Response Signature v2
[path] License API/License API Authorization/

## Overview

Response objects from License API endpoints contain an http header `LicenseSignature` which is an HMAC-SHA256 signature used to verify the integrity and authenticity of the response. This is not the same as the `license_signature` in certain response objects (see [**Response Signature**](docId\:ouciGcAGCAIKAdWCbx9Wk) for that property).

The LicenseSignature header signs the entire response object using our private key, which enables you to use our public key to verify the signature.

## Verifying Response Signature v2

You can use the server's public key to verify the LicenseSignature header. By validating the signature, you ensure the response originates from LicenseSpring's trusted servers.

Download the server public key from the link below to implement signature verification using the example provided:

::File[]{src="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8_-OM1Oqw9QE45OBPr7Mt_prod.pub" signedSrc="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8_-OM1Oqw9QE45OBPr7Mt_prod.pub?AWSAccessKeyId=AKIAYQNQCIXNIQWBC56C&Expires=1691668099&Signature=kmfNsu%2BwWFWhPnWVh5gC3BpA2L4%3D" label="prod.pub"}

## Code Sample

```javascript
import crypto from 'node:crypto'
import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc.js'

dayjs.extend(utc)

// Header and response received from our servers:
const responseLicenseSignatureHeader = '...';
const responseBody = {
  // ... response object from LicenseSpring's server ...
};

/* 
  NOTE: specifically for the Activate License Offline endpoint, existing
  signatures in the response body need to be removed before calculating
  the v2 signature, like this:
  
  delete responseBody.license_signature;
  delete responseBody.license_signature_v2;
*/

const verifier = crypto.createVerify('RSA-SHA256');
verifier.update(JSON.stringify(response));
const result = verifier.verify(publicKey, responseLicenseSignatureHeader, 'base64');

console.log(result); // will be "true" if signature is valid
```


[title] License Features Import
[path] Vendor Platform/Importing/Exporting Data/

Importing license features allows you to upload multiple features in bulk, expediting the process of managing and associating features with licenses. This page outlines the steps for importing license features using both the platform interface and the Management API.&#x20;

## Importing License Features via Platform Interface&#x20;

### 1. **Navigate to the License Features Import Section**

- Open the `Licenses` menu in the sidebar and select the `License Features Import` tab, as shown below.

![License Features Import Tab](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Ql-1eNndEtIaIHEvC5_zZ_image.png "License Features Import Tab")

### 2.  Prepare Your CSV File&#x20;

- Populate your CSV file with your license data. Ensure you include the **required headers**, such as `license_key` and `code`.
- There are other [**optional headers**](https://docs.licensespring.com/management-api/license/import-license-features#KYLkE) that can be included in this CSV file for more detailed configurations, such as `max_consumption` and `expiry_date`.
- Optionally, you can click the `Download import template file` button to download a pre-formatted CSV file. This template ensures your data conforms to the required structure. This template is also included below:

::File[]{src="https://archbee-doc-uploads.s3.amazonaws.com/1qQvw4Dswzp513JIpU4f9-rGr6MwzZl96SU_grO6qn4-20241204-021000.csv" signedSrc="https://archbee-doc-uploads.s3.amazonaws.com/1qQvw4Dswzp513JIpU4f9-rGr6MwzZl96SU_grO6qn4-20241204-021000.csv" label="lpf_example.66d33fd0.csv"}

### 3. Upload Your CSV File&#x20;

- Drag and drop your prepared file into the upload area or click to browse and select your file. The platform accepts `.csv` files only.

![CSV Upload Area](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/1xgF-RmvZol-5fxa-ybGr_image.png "CSV Upload Area")

### 4. Monitor the Upload Status&#x20;

- Once uploaded, the platform will validate your data and display the status in the `Imports List` section.
- If successful, the status will show as `success`. Otherwise, review the error messages, correct the data, and re-upload.

![Imports List and Status](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/niuQfeBzxZlCQhNgrc2v9_image.png "Imports List and Status")

## Importing License Features via Management API&#x20;

For users who prefer programmatic imports, the Management API provides a simple endpoint to import license features from CSV files.&#x20;

More information regarding this style of importing can be found at [**Import License Features From CSV**](docId\:xVV2D4_AFjW3oXx3tOm5J), our page outlining the Management API endpoint for performing the equivalent action.

[title] License Import
[path] Vendor Platform/Importing/Exporting Data/

Importing licenses refers to the ability to bulk upload license data efficiently using a pre-defined CSV file. This page walks you through the entire process, including where to find templates, how to structure your CSV file, and how to upload it through the platform interface or Management API.&#x20;

## Importing Licenses via Platform Interface&#x20;

### **1. Navigate to the Licenses Import Section**

- Go to the `Licenses` menu on the sidebar and click the `Licenses Import` tab, as shown below.

![License Import Tab](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/bP0U-45NEF_B72RBDosul_image.png "License Import Tab")

### 2.  Prepare Your CSV File&#x20;

- Populate your CSV file with your license data. Ensure you include the **required headers**, such as `license__license_key` and `product__short_code`.
- There are other [**optional headers**](https://docs.licensespring.com/management-api/license/import-licenses#YCN0Z) that can be included in this CSV file for more detailed configurations, such as `license__max_activations` and `license__validity_period`.
- Optionally, you can click the `Download import template file` button to download a pre-formatted CSV file. This template ensures your data conforms to the required structure. This template is also included below:

::File[]{src="https://archbee-doc-uploads.s3.amazonaws.com/1qQvw4Dswzp513JIpU4f9-5LIH-vNz5kVTNoHEf1dBY-20241204-011307.csv" signedSrc="https://archbee-doc-uploads.s3.amazonaws.com/1qQvw4Dswzp513JIpU4f9-5LIH-vNz5kVTNoHEf1dBY-20241204-011307.csv" label="license_import_template.31dc5f35.csv"}

### 3. Upload Your CSV File&#x20;

- Drag and drop your prepared file into the upload area or click to browse and select your file. The platform accepts `.csv` files only.

![CSV Upload Area](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/g-xFiw0DsqWTKMsst4HPK_image.png "CSV Upload Area")

### 4. Monitor the Upload Status&#x20;

- Once uploaded, the platform will validate your data and display the status in the `Imports List` section.
- If successful, the status will show as `success`. Otherwise, review the error messages, correct the data, and re-upload.

![Imports List and Status](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/EjOI__l6L_AqhVKAZlf9I_image.png "Imports List and Status")

## Importing Licenses via Management API&#x20;

For advanced users, the platform also supports license imports programmatically through the Management API.

More information regarding this style of importing can be found at [**Import Licenses From CSV**](docId\:P8KUpKwpexBgzJC2W3Bht), our page outlining the Management API endpoint for performing the equivalent action.

[title] License Export
[path] Vendor Platform/Importing/Exporting Data/

The license export feature enables you to extract license data into a CSV file for reporting, analysis, or backup purposes. Using filters, you can customize the export to include only the data you need. This page provides step-by-step instructions for exporting licenses through the platform interface.

## How to Export Licenses from the Platform

### **1. Navigate to the Licenses Section**

- Open the `Licenses` menu from the sidebar and select `All Licenses`, as shown below:

![All licenses tab](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/704Fs-8VkLqHcysSkMrwo_image.png "All licenses tab")

### **2. Apply Filters (Optional)**

- Use the `Search Filters` option to narrow down the licenses to be exported.
- Available filters include:
  - **Customer Labels**: Filter licenses by associated customer labels.
  - **Is Disabled**: Include or exclude disabled licenses.
  - **Expiration Date**: Filter licenses based on their expiration date.
  - **Product**: Export licenses associated with a specific product

![Search filters button](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/h54vE50VsuZnmyvzeU78N_image.png "Search filters button")

### **3. Initiate the Export**

- Click the `Export Licenses` button located in the top-right corner of the licenses page.

![Export licenses button](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/BE9SEntgyDgezjFUN_NL2_image.png "Export licenses button")

### **4. Set Export Options**

- In the **Export Licenses** dialog:
  - Choose a **date range** for the licenses you want to export.
  - Review and confirm any applied filters.
  - Clear filters directly in this dialog if necessary.

![Export Options Pop-Up](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/CMj4_wOHQMaevHcHZLZz3_image.png "Export Options Pop-Up")

### **5. Confirm and Export**

- Click the `Confirm` button to start the export process.
- The platform will generate a CSV file containing the license data that matches your filters.

## Exporting a License via Management API&#x20;

Exporting licenses via Management API is handled with the same endpoint as with orders. Visit our [**Orders Export page**](https://docs.licensespring.com/orders-export#aL7mt) for more information on programmatically exporting licenses, both individually and in bulk.

[title] OAuth Configuration
[path] Vendor Platform/Settings/

OAuth authorization is an alternative authentication mechanism for the License API, available exclusively for **enterprise clients**.

## OAuth Client ID and Secret Structure

OAuth credentials (Client ID and Secret) can be associated with different levels of specificity within the system:

- **License**
- **Customer**
- **Customer Account**
- **Company**

### OAuth Token Validation Hierarchy

When validating OAuth tokens, the system follows a hierarchy of specificity:&#x20;

1. Check for an OAuth secret at the **License** level.
2. If not found, check at the **Customer** level.
3. If not found, check at the **Customer Account** level.
4. If not found, check at the **Company** level.

### User Interface Access

- **License, Customer, and Customer Account Views**: OAuth settings are accessible via the **OAuth tab**.
- **Company Level**: OAuth settings can be found under **Settings → Keys**.

![OAuth Initialization Location on Platform](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ES7lW5SgBaDdKd_Oc-WYK_image.png "OAuth Initialization Location on Platform")

## Default Rotation Settings

- When creating new OAuth credentials, the system applies **default rotation settings**, unless overridden for specific credentials:
  - **Secret Expiration Period**: Defines the time before a newly generated secret expires.
  - **Secret Rotation Grace Period**: Specifies the period before the current secret expires, allowing for a smooth transition.

![Setting the Default Rotation Settings](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/_pV4Mf4EcNgdrYbswpHfy_image.png "Setting the Default Rotation Settings")

## Enforcing OAuth Authentication

A company account may have an optional flag, `is_oauth_required`, when enabled:

- OAuth authentication is **mandatory** for all users under that company account.
- API key and shared key authentication methods are **disabled**.

This setting is available under **Settings → Preferences**&#x20;

### API Error Response

If a request is sent using an API/shared key while OAuth is required, the License API will return the following error:

```json
{
    status: 400,
    code: 'oauth_required',
    message: 'This account requires OAuth authentication'
  }
```

## Authorization Process

To authorize with OAuth:

1. Users obtain a **short-lived access token** using their **Client ID** and **Secret**.
2. The access token must be included in the **License API request headers**, replacing the traditional API key or shared key.

For more details, refer to [**OAuth Authorization**](docId\:xhYZAUaL9QY4jerxKilmk).&#x20;

## SDK Integration

OAuth authentication will be implemented in the SDKs to simplify integration. See your SDK specific documentation for more information.

## OAuth Key Management

### License Manager Permissions

License managers can:

- View a list of client IDs and secrets for the licenses and customers they manage.
- Revoke OAuth secrets.
- Manage expiration dates of OAuth secrets.

### Explicit Permission Requirement

License managers can **only** revoke or modify expiration dates of OAuth keys if they have been granted explicit permission to do so.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/QnujVsQqivOAAiHtJWQ9t_image.png)

## OAuth Expiration Notifications

Platform users can define **notification policies** for OAuth key expiration. These policies trigger email notifications when:

- A secret is about to expire.
- A secret has already expired.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/5xN2go7wSphegaLCWZvom_image.png)


[title] Customers Import
[path] Vendor Platform/Importing/Exporting Data/

Importing customers from CSV allows you to quickly upload customer data in bulk, saving time and ensuring consistency when managing customer information. This page provides step-by-step instructions for using both the platform interface and the Management API to import customer data.&#x20;

## Importing Customers via Platform Interface&#x20;

### **1. Navigate to the Customers Import Section**

- Open the `Customers` menu in the sidebar and click the `Customers Imports` tab

![Customers Imports Tab](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/lZ-HHPTh4XWFBpm_l0M8a_image.png "Customers Imports Tab")

### 2.  Prepare Your CSV File&#x20;

- Populate your CSV file with your license data.&#x20;
- There are other [**optional headers**](https://docs.licensespring.com/management-api/customer/import#Ed8Wl) that can be included in this CSV file for more detailed configurations, such as `first_name` and `last_name`.
- Optionally, you can click the `Download import template file` button to download a pre-formatted CSV file. This template ensures your data conforms to the required structure. This template is also included below:

::File[]{src="https://archbee-doc-uploads.s3.amazonaws.com/1qQvw4Dswzp513JIpU4f9-fbfYPoMmkPPqxNby5YDHt-20241204-022545.csv" signedSrc="https://archbee-doc-uploads.s3.amazonaws.com/1qQvw4Dswzp513JIpU4f9-fbfYPoMmkPPqxNby5YDHt-20241204-022545.csv" label="customers_import_template.95c819f1.csv"}

### 3. Upload Your CSV File&#x20;

- Drag and drop your prepared file into the upload area or click to browse and select your file. The platform accepts `.csv` files only.

![CSV Upload Area](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/uvGBSYBnhY7MB_sP9Nlsk_image.png "CSV Upload Area")

### 4. Monitor the Upload Status&#x20;

- Once uploaded, the platform will validate your data and display the status in the `Imports List` section.
- If successful, the status will show as `success`. Otherwise, review the error messages, correct the data, and re-upload.

![Imports List and Status](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/FoSjZa4re3drSPnIo5ozc_image.png "Imports List and Status")

## Importing Customers via Management API&#x20;

For users looking to programmatically import customer data, the Management API provides this functionality.&#x20;

More information regarding this style of importing can be found at [**Import Customers from CSV**](docId\:o-XpEnl-n8N8dwqwrE8pF), our page outlining the Management API endpoint for performing the equivalent action.

[title] Devices
[path] Vendor Platform/

This summary page displays a list of all license devices that have been used to activate your account licenses.

![License Devices View](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/2_INm6iOaTQZg4ga5_aQ6_image.png "License Devices View")

For every device you can inspect for which license was this device used and which license user ( if user based authorization ).

:::hint{type="info"}
The same device, with the same hardware\_id can be used to activate multiple licenses, and it will be displayed multiple times in the devices list since for every new license activated, LicenseSpring creates a new license device.
:::

## Device Details

**Devices Tab:&#x20;**&#x53;hows all machines where a license has been activated. You can view the device’s hardware ID, activation type, OS, SDK version, network information, status, and other variables. Expanding a device provides detailed info including first activation date, hostname, IP addresses, MAC address, and whether the device is a virtual machine.&#x20;

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/JVyEFYI1pqR8K7-1bkuB3_image.png "Device Details")

### Expanded Device Details&#x20;

- **First Activated** – The date when the license was first activated on this device.
- **Activation Type** – Indicates whether the license was activated online or offline.
- **OS** – The operating system running on the device.
- **SDK Build** – The version of the LicenseSpring SDK used by the application.
- **App Version** – The version of the application that is using the license.
- **Hostname** – The name of the device or computer.
- **External IP Address** – The device’s public network IP address.
- **IP Address** – The local network IP address of the device.
- **MAC Address** – The unique identifier of the device’s network interface.
- **Is Virtual Machine** – Specifies whether the device is a virtual machine.
- **VM Info** – Additional information about the virtual machine, if applicable.


[title] Metadata Filter Usage
[path] Vendor Platform/Metadata/

Metadata filters in LicenseSpring allow you to **search and narrow down entities** (licenses, products, customers, orders, etc.) based on the custom metadata attached to them. This provides a flexible and powerful way to manage and find relevant information directly within the platform without needing API calls.

## Supported Pages

Metadata filters can be applied on:

- **License:** Filter licenses by activation date, type, or custom tags.&#x20;
- **License Manager:** Filter licenses by user or role metadata.&#x20;
- **License Users:** Find license users based on license or user metadata.&#x20;
- **Customer:** Search customers by preferences, region, or custom identifiers.&#x20;
- **Customer Accounts:** Filter customer groups by account-level metadata.&#x20;
- **Products:** Filter products by version, release date, or custom attributes.&#x20;
- **Orders:** Search orders by source, payment type, or special instructions.&#x20;

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/q6XPPYQ8zZ_rPLc3OlEL2_image.png "Metadata Filters")

## Metadata Filters Panel

Use the **Metadata Filters Panel** to create and apply metadata-based filters.

### **Main Fields:**

- **Path:** Metadata key (e.g., customer.region).&#x20;
- **Operator:** Comparison type (equals, contains, etc.).&#x20;
- **Value:** Value to match (e.g., "production").&#x20;
- **Type:** Data type (string, number, boolean, object, array, null).&#x20;
- **+ Add Filter:** Add multiple filters to refine results.&#x20;
- **Preview:** See filters before applying.&#x20;
- **Actions:** Apply or clear filters.&#x20;
- **Advanced Mode:** Enable complex queries.&#x20;

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/8T_ZHMB14bp5HB0q99qqk_image.png "Metadata Filter Panel")

## Filter Types

Supported metadata types with examples:

- **String:** metadata\_\_customerName="Acme Corp"&#x20;
- **Number:** metadata\_\_maxUsers=100&#x20;
- **Boolean:** metadata\_\_isTrial=true&#x20;
- **Null:** metadata\_\_assignedUser=null&#x20;
- **Object:** metadata\_\_deployment.environment="production"&#x20;
- **Array:** metadata\_\_tags="KeyAccount"&#x20;

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/OLNsiSbERFf4rlO3nooC8_screenshot-10-27-2025-140105.png "Filter Types Dropdown")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/tRpwR3dFWwshoXp4CF87W_screenshot-10-27-2025-144126.png)

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/tygXSVCjt2xIjMRZwAr7a_screenshot-10-27-2025-141651.png "License Page Metadata Filter Result")

:::hint{type="success"}
For full **JSON-format examples** of metadata filtering (including nested objects, arrays, numbers, booleans, and null values), see the [**“Metadata Filtering”**](https://docs.licensespring.com/management-api/metadata-filtering) section of the LicenseSpring Management API documentation.&#x20;
:::

## Advance Mode Filter Syntax

Advanced Mode Filter Syntax In **Advanced Mode**, you can enter metadata filters as a **raw query string** using metadata\_\_-formatted keys.

- Filters follow a key-value structure, where keys match metadata fields and values match stored metadata.&#x20;
- Nested objects use double underscores (\_\_) to navigate deeper levels.&#x20;
- Multiple filters are combined with AND logic.&#x20;


![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/SCEJLORC3MBDkKc3fcp42_screenshot-10-27-2025-140711.png "Advance Mode Turned ON")

**Enter metadata filters as a raw query string, using metadata\_\_-formatted keys.**
***Example:***

:::CodeblockTabs
Raw Query

```tex
metadata__deployment__environment="production" AND metadata__isTrial=true
```
:::

This mode is ideal for **complex queries** or when you want to enter multiple filters quickly.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/7twuqlOg2nuKjYqMpHoXf_image.png)

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/7twuqlOg2nuKjYqMpHoXf_image.png "Adding Metadata on Product Page")

:::hint{type="info"}
- When **Advanced Mode** is enabled and you enter a raw query string, the panel will **automatically populate the corresponding filter fields**.&#x20;
- This makes it a **useful reference** for understanding how your query translates to individual filters.&#x20;
- Once the fields are populated, the **Preview section** will display the raw query for verification before applying the filters.
:::

## Tips & Best Practices

- **Check Metadata Keys**: Use the exact key names as defined in your metadata JSON.&#x20;
- **Case Sensitivity**: Metadata keys and string values are case-sensitive.&#x20;
- **Preview Before Applying**: Use the preview panel (if available) to confirm filter results before applying them.&#x20;
- **Use Objects Carefully**: Filtering on nested objects requires the full path in key format.&#x20;


[title] Customer Accounts
[path] Vendor Platform/

LicenseSpring allows customers to be grouped by account. This is useful if you license software to an organization with different departments, or multiple locations, and can be found by expanding the "Customers" tab in the left-hand navigation.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/jzejGCFWHz8wjd1KjTvbH_image.png "List of Customer Accounts")

The columns in the accounts table include:

- `Name`  Account name
- `Code`  Account code
- `Number of customers` Number of customers that belong to a specific account
- `Email` Email address associated with the account
- `Reference` Optional value that can be useful when searching for an account

To retreive information on the account without moving from the summary page, click on the dropdown arrow next to the account `Name`:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Zuk3ArSx1iPQr_e3gTAkj_image.png "Customer Accounts Detail View")


[title] Activate a Key-Based License
[path] Getting Started/

In order to perform license activations or license checks, your software needs a way to interact with the LicenseSpring service.

For that you can either make calls directly to the LicenseAPI, or you can use one of the SDKs that we maintain.&#x20;

:::hint{type="info"}
To keep things simple, we assume you selected license keys as your authorization method.
:::

:::hint{type="info"}
There are many good reasons why you would call the LicenseAPI directly. However, the server response is in JSON which you would be responsible for parsing. We usually recommend that you use one of our SDKs, since give you a lot of additional functionality, such as performing local license checks, and working with the licenses as objects and calling functions on them, which could potentially save you a lot of time.
:::

Regardless of whether you are using the LicenseAPI directly, or importing one of our SDKs in your codebase, you will need to enter the some of the following information at a minimum.

## Connecting to the API

You will need your **api key** and your **shared key**. You can find these by logging in to the vendor account, and navigating to settings > keys. Click on the dropdown button beside the api key to reveal your shared key:

![Location of API Key and Shared Key](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/LQ_9u7KBynKGGoNgdmYi4_image.png "Location of API Key and Shared Key")



![]()

:::hint{type="info"}
Alternative to api and shared key is [**oAuth authorization**](https://docs.licensespring.com/oauth-configuration).
:::

The minimum information required in order to run the `activate_license` webhook (or its respective SDK) for a key based license is:

- License key
- Product code
- HardwareID (a unique identifier for the device you are binding a license to).

If the activation is successful, the status of the license will say "Active", and the "Total activations" will have incremented by `1` .

![License Status](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/OX0do4KBh17xVW2RT4Weh_image.png "License Status")

![]()


[title] Creating & Configuring Products
[path] Getting Started/

## What Is a Product in LicenseSpring?

A `Product`  is a basic building block within the LicenseSpring universe. It typically represents your software application, but it can be many other things, such as controller, an operating system, a plugin etc.

You can define products, configure features and custom fields for products, create license policies for products, archive products, or reactivate an archived product.&#x20;

## How to Define a New Product

Log in to the LicenseSpring Vendor Platform and click on `Configure Products` :

![Configure Products Button](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/U6NY8ac6EnycuG7vqO29J_image.png "Click on Configure products")

![]()

This takes you to the section that lists all of the products you have already defined in your account. From here, click on `Add a new Product` in the right corner:

![Add New Product Button](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/KrmC6AHQrnbMoFVSLFYwi_image.png "Click on Add New Product Button")

Next, you will be asked to fill in some basic information about your product:

- **Product Name**: This must be a unique value
- **Product Code**: This must be a unique value and cannot be changed once a product is defined
- **Authorization Method**: Select whether you want to issue license keys, or assign users to licenses
- **Floating Timeout**: Optional configuration for the default "heartbeat" when you issue floating licenses
- Whether or not you allow Trial licenses to be issued
- Whether you want binaries and versions associated to a product

![Defining New Product](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/CLMInfoL46iy5kLYKkinD_image.png "Fields required when defining a product in LicenseSpring")

Once you are finished, click next to review the product information you entered, and then click "create product"

![Click Create Product Button](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/oL6d4_tOBFTG2UuN6f1P__image.png "Finish the product definition by clicking on \"Create product\"")

![]()

You will immediately be on the product detail page for your newly defined product.

You can now start issuing licenses for this newly defined product!

If you like to live dangerously, feel free to explore the use of product features, custom fields, product versions or defining license policies, all of which can be configured on the product details page.

![Finished Product Details Page](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/qVG3Y5-u7USx7wRg7q9s__image.png "Finished Product Details Page")


[title] Opening an Account
[path] Getting Started/

While our publicly available documentation includes browsing capabilities and the option to download our SDKs, certain essential functionalities like obtaining API keys, defining products, and issuing new licenses require users to create an account with us.&#x20;

Once you have an account, you can access these additional features to integrate our services seamlessly into your applications.

## Types of Accounts Available

As of the current date, we offer four types of accounts, each tailored to cater to specific requirements related to the sophistication of the software entitlement mechanism desired by the vendor, as well as the volume of API requests needed.&#x20;

For a detailed understanding of the available tiers and their associated features, I recommend referring to our [**pricing page**](https://licensespring.com/pricing/).&#x20;

There, you will find comprehensive information about the different account types, their capabilities, and the corresponding costs to help you choose the one that best suits your needs.

## How to Open an Account

If you haven't done so yet, please complete our [**contact form**](https://licensespring.com/get-started/). Once received, our staff will review your information to ensure LicenseSpring is the right fit for your needs.&#x20;

Upon verification, we will create your account and send you the login credentials.

:::hint{type="info"}
**Note:&#x20;**&#x59;ou will receive an account activation invitation via the email you provided. This activation invitation has a validity of **three days**, so it's essential to activate your account within this period. Otherwise, you will need to get in touch with us and request a new activation invite.
:::

![LicenseSpring Sign-Up Page](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/K0h2ohMcgQjccWsICWXbS_image.png "Complete our sign-up form, and your account will be promptly opened.")


[title] Products
[path] Vendor Platform/

## **Product List Page – What You Can Do**

The **Product List** page is your main dashboard for managing all products in your system. It helps you easily find, review, and organize products, as well as create new ones. Here’s what you can do on this screen:



![Product List View](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/DtHsF01xB1wnXh6YO3-I7_image.png "Product List")

### 1. **View and Organize Products**

**Active & Archived Tabs**
&#x20;Switch between viewing active and archived products using the tabs at the top.

**Product Table Overview**
&#x20;Each row in the table displays key product details:

- Product Name
- Product Code
- License Policy (e.g., Default or custom policy)
- Authorization Method (License Key or User-Based)
- Trial Availability
- Bundle Status (if it's part of a bundle)
- Product Status (Active or Archived)

### 2.  **Search and Filter**

**Search by Name**
&#x20;Quickly find a product by typing its name into the search bar.

**Advanced Filters**
&#x20;Click **“Search filters”** to filter the list by:

- **Authorization Method**: License Key or User
- **Trial Availability**
- **Status**: Active or Archived

**Clear Filters**
&#x20;Use the “Clear filters” button to reset all filters and view the complete list.

### 3.  **Add New Products or Bundles**

- **Add New Product**: Create a new product entry.



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/yLG2ENjQWV4LWgyrEes4o_image.png)

- **Add New Bundle**: Group multiple products into a bundle.

Both actions can be done directly from this page for quick and seamless product management.

### 4.  **Navigate Large Product Lists**

Use the **“Previous”** and **“Next”** buttons at the bottom of the page to move between multiple pages of products.

### 5.  **At-a-Glance Product Insights**

Without needing to open individual product pages, you can instantly see:

- Which products allow trials
- Which are part of a bundle
- Current product status

### &#x20;**Summary**

The **Product List page** is designed for fast, efficient product management. Whether you're updating product details, organizing licenses, or expanding your catalog, this page provides a clear, centralized interface to help you stay in control.

[title] Customers
[path] Vendor Platform/

This view will present a table with all of the customers that have been specified within LicenseSpring.

Common tasks you can accomplish on the customers summary view include:

- Looking up customers
- Defining customer labels
- Add a new customer to LicenseSpring
- Download a CSV file with all customers

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/EnqS5UJvcAkxrHvkLc5aL_image.png "List of All Customers")


[title] Product Versioning
[path] Product Configuration/

The LicenseSpring service can be configured to return product version information on Activation, license checks, and other webhooks through the License API.

:::hint{type="info"}
LicenseSpring does not host binaries to product versions. We simply provide a mechanism to handle product versions for a license
:::

## Add a Version to a Product

To add a new version of your product, open the product detail page, and click the Versions tab, and then click "Add new version"

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/YVDxhh9RgKbMMqZC0LTSH_image.png "Adding New Product Version")

## Product Version Fields

### Required Fields

- `Environment`&#x20;
- `Version Number`&#x20;
- `Release Date`&#x20;

### Optional Fields

- `Requires Version` Specify what is the minimum version required for someone to be able to update to the version being added. For example, if you are adding a new version 3.0.0 and you set "Requires version" to 2.0.0, then anyone with a version less than 2.0.0 will not be able to upgrade to 3.0.0
- `File hash`  MD5 which you can use to help verify the integrity of the binaries being installed
- `File size` Defined in bytes, is communicated so that you can display this information when offering a new version update
- `Link to file` Link to download the binaries of the new version
- `Link to release notes` Intended as a web page or text file to display release notes on the version
- `Link to EULA` Intended to show a web page or text file with the License Agreement for the app or unique to the app version
- `Channel` Could potentially refer to a specific distribution or release channel for your software product versions. In software development, different versions of a product may be released to various channels or groups of users based on factors like stability, testing, or deployment strategy. These channels typically serve different purposes and cater to different user needs.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/BYgQOB2DcQFa0I8DUfLcC_image.png)

## Using Product Versions

The License API has a [**Get Product Versions**](docId\:mBq0eK4XlT_jX8SLdyHY9) webhook that allows you to retrieve all product versions for a given channel and environment. You can compare the release date of a product version with another timestamp, such as a license expiry date or maintenance window to determine whether the version is allowed for this license.

Similarly, you can check the latest product version against the version currently installed to conditionally prompt the user to download an update to their software using [**Get Installation File**](docId\:LxPe6kV-OLj7HLL-GrL1q) endpoint.

### Link License to max product version

LicenseSpring supports linking licenses to specific product versions, allowing fine-grained control over license applicability. This feature enables scenarios where a license should only be valid up to a designated version of a product.

![Product version on a license](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/SJD5EKhdE9AgyxcnucJp__image.png "Product version on a license")

If a license is linked to a version, any license check or activation request must respect this version limit.

When a license is linked to a product version:

- The client may send the app\_ver parameter to specify the version of the product they’re using.
- If the app\_ver is newer than the version linked to the license, the API will return `product_version_not_supported` error.

:::hint{type="warning"}
This can be verified only if `app_ver` parameter is sent with license activation ( online and offline ) and check requests.
If a license is not linked to any product version, then no version validation is enforced.
Version validation is possible only if versions follow [**semantic versioning**](https://semver.org/) format.
:::

Product version can also be applied to a license policy. If a license is created via a license policy, and that policy has a product version assigned to it, the license inherits it.



:::hint{type="danger"}
License bundles are not supported with product version linking.
:::




[title] Product Features
[path] Product Configuration/

What Is a Product Feature?

In LicenseSpring, a Product feature is an attribute that is defined for a given product, and can be added to any license issued for that product. In LicenseSpring, we define two product feature types:

### Activation Feature

![Adding Product Feature](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/rhVvZvQRgFlZHQ3G-ih-L_image.png "Adding Product Feature")

Activation Features are meant to be used to turn on or off specific functionality within your licensed product, such as a component, module, or set of features.

Once defined for a product, an activation feature can be added or removed from a license, without additional functionality.

### Consumption Feature

Consumption Features are meant to meter the usage of a component or resource, such as an API, the number of times a Report is generated, or amount of time (in seconds or minutes) that a resource is used.

Consumption features, like Activation features, can be added or removed from a given license. However Consumption features also have the attributes `Max consumption` , allow overages Boolean,  a `Max overages`  value, and a means to reset the consumption allowances periodically.

![Consumption Period Selection](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/0L47MfovPRg_4H5PkkcNg_image.png "Consumption Period Selection")

### Time limited features

Optionally you can define an expiration for the features. You can either set expiration to a specific date ( `Expiry date` ) or you can set a Valid duration to a feature which is then used to calculate a specific expiry date at the time of the first license activation.

Features that do not have expiry\_date defined, are never expired.

License API will also return `is_expired` Bool for every feature. To include expired features to a license check and license activation response, use[**&#x20;include\_expired\_features**](https://docs.licensespring.com/license-api/check) parameter.

Feature expiration policy can be defined on a product features, license feature and license policy level.

![Feature Expiration Settings](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/aaiUAGOlpIPJOgsMu-cUj_image.png "Feature Expiration Settings")

### Floating features

Features can also be configured to support concurrent usage, same as on a license level.

More details about this usage can be found [**here**](https://docs.licensespring.com/license-entitlements/floating-features).

:::hint{type="info"}
Depending on your plan you will have access to a certain number of Features and there may be limitations on the type of feature you are allowed to use.
:::

## Define a New Product Feature

### Required Fields

- Feature Name
- Feature Code

### Fields for Consumption Features

- Max Consumptions
  - Allow Unlimited Activations
- Allow Overages
  - Max Overages
- Reset Consumption
  - Consumption Period

Once you defined a product, click on the "Features" Tab, and click "Add product feature"

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/I3fNT2vpIG2r5nqVPOXxA_image.png "Adding New Product Feature")

Give the Feature a Name, a Code, and select its type.

::Image[]{alt="Selecting Product Feature Type" src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/r_-sZa_JyefYXQKKE3eIW_image.png" size="70" width="780" height="526" caption="Selecting Product Feature Type" position="center" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/r_-sZa_JyefYXQKKE3eIW_image.png"}

If the feature is of type consumption, set the default value for Max Consumption, the Value for Max Overages, as well the time interval for which the allowances should reset

::Image[]{alt="Adjusting Consumption Period" src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/pYe8OwPkIAupoUNRi3VFg_image.png" size="82" width="784" height="896" caption="Adjusting Consumption Period" position="center" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/pYe8OwPkIAupoUNRi3VFg_image.png"}

:::hint{type="info"}
Adding default allowances for a product feature can always be changed when issuing a new license, or by modifying the entitlements of an existing license. For more information, please visit the "Features" article in the "License Entitlements" section.
:::

## Editing/Deleting Product Features

:::hint{type="info"}
You can rename a product feature, and the default values for consumption features can be modified. However, you cannot change a product feature code.
:::

:::hint{type="danger"}
If you delete a product feature, it will be removed from any licenses that are currently using it. Adding the feature back to the product will not add the feature back to the licenses. LicenseSpring does not have any concept of archiving features!
:::

To edit a product feature, go to the features list and click on the Pencil icon on the row for that product feature.

To delete a product feature, click on the red garbage can icon on the row for that product feature.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/oM8duY-aQhHEiVI6_wmRx_image.png)

## Feature groups

On a product level, you can group features to groups for easier feature licensing.
When issuing licenses you do not need to list all of the features you want for this licenses - you just define a group and attach a group code during order creation.

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/AAbA3zxpTlgyx8f3nrT63_image.png "Feature Groups Tab")

Groups behave similar to license policies in a way that you can also define time limited settings on a group level that would be applied to all license features when license is created.

![Adding Feature Group From](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Uriwr2ATbw4kmbLbzbgE__image.png "Adding Feature Group From")

Feature groups can be applied to a license policy or used directly when creating order.

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/HLwBqAPgMdaWtWLyNH_u9_image.png "Edit License Policy View")

:::hint{type="info"}
If you at the same time apply a feature both as a standalone feature and in a group, a standalone feature settings will apply.
:::


[title] Air-Gapped License Activation
[path] License Entitlements/License Activation Types/

Our concept for air gap license activations is similar to the offline activation process, with the added constraint that files cannot leave the private network after the licensable software has been installed/deployed.

:::hint{type="info"}
Only key-based licenses can be activated as air-gapped licenses for now.
:::

## General Workflow for Issuing & Activating Air-Gapped Licenses

1. Add the air-gapped API key to the client SDK
2. Create an air-gapped license (either from a license policy or overriding an existing one)
3. Generate an initialization code with the license key from the air-gapped portal
4. Enter the license key and initialization code in the client application
5. Generate an activation code using the SDK
6. Generate a confirmation code from the air-gapped portal
7. Complete the activation process by entering the confirmation code in the SDK.

The air-gapped activation portal can be found here: [**airgap.licensespring.com**](https://airgap.licensespring.com/)

:::hint{type="info"}
[**Contact us**](https://licensespring.zendesk.com/hc/en-us/requests/new) to white label the air-gapped portal for your own subdomain!
:::

## Creating Air-Gapped Private/Public Keys

The key pairs can be regenerated, however the new public key would need to be re-entered into the SDK. The air gapped public key should be obfuscated inside of the SDK.

The key algorithm used for air gap company account keys and air gap license keys is [**EcDSA**](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm). You can find the air-gapped private and public keys under "account settings" > "keys".

:::hint{type="warning"}
This step is **essential** for **Air-Gapped** licenses
:::





![generating new key pair](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/pIF39hOG5pZteSG9rtBIQ_image.png "Generating new key pair")

##

![Generated air-gapped keys](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/xK-vhPsQ498572HJ6zkwP_image.png "Generated air-gapped keys")

## Create a License Policy for Air-Gapped Licenses

On the product detail page, go to the `License policies` tab and click on the "add license policy" button.

To mark policy as air-gapped switch the "set as air-gapped" toggle.

:::hint{type="info"}
Air gap license policies cannot be edited or deleted after they are created. The same is true for any air gapped license that has been issued.
:::

![Setting License Policy as Air-Gapped](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/EteaCntp8IbnlEu3b766a_image.png "Setting License Policy as Air-Gapped")

## Issuing Air-Gapped License Keys Through the Vendor Platform

Start the process as you would with any license: Click on the licenses tab in the left navigation > "Issue Licenses". When adding a product to the order, toggle "Set as air-gapped". All of the policies selectable from the drop-down will only be the policies defined as air-gapped:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/sDcT_oH0IkyyaW_xvuMO-_image.png)

The air gapped license is now created

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/MrOgYnTnSPQqVIjnKklR7_image.png)

## Activating an Air-Gapped License

The air gap portal for license activation can be found at: [**airgap.licensespring.com**](https://airgap.licensespring.com/)

The process of activation is done in 3 steps including actions on server (portal) and SDK.

### Step 1: Generate an Initialization Code From the Air-Gap Portal

Navigate to the air-gap portal, and click "Initialize air-gapped activation", enter the license key:

![Initializing Air-Gap Activation](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/08H2sUpQQ6vQwvVMYwdc8_image.png "Initializing Air-Gap Activation")

The portal will return an initialization code which, along with the license key needs to be entered in the SDK.&#x20;

There is a QR code available to make the process of copying this information easier:

![Initialization Code](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/NZDO80W8NtOq1RP4RmnUY_image.png "Initialization Code")

```json
{
	license_key: "GQXR-94AC-QKAK-B4GP",
  	initialization_code: "+48Wk6FQIwAmFctO6Ru8YHIX849wCKilMBH149sn9yo="
}
```

### Step 2: Generate Activation Code From the SDK

This `initialization_code` must be imported to the SDK alongside with the license key. The SDK will verify the `initialization_code` and if successful will return the `activation_code`, along with the `hardware_id` values to the user so that user can take those strings back to the server.

### Step 3: Generate Confirmation Code From the Air-Gap Portal

On the air-gap portal, click "Enter Air-Gapped Activation Code"

Enter the license key, `hardware_id`, and `activation_code`

![Entering Air-Gap Activation Code](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/jsJ2xcHYshwz29ZZ1bDs4_image.png "Entering Air-Gap Activation Code")

![Pop-Up To Enter Activation Code](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/j47yarz3XUmCatjGVwPMs_image.png "Pop-Up To Enter Activation Code")

The portal will return a policy ID and a confirmation code, as well as a QR code to make it easy to copy/paste this information.

:::hint{type="info"}
At this point, LicenseSpring will consider this license has been fully activated, even if the confirmation code and policy ID were not entered into the client application
:::

:::hint{type="danger"}
**Important:** If incorrect data (e.g., an invalid policyFilePath) is entered into the client application during the confirmation step, the LicenseSpring SDK will throw an error, and no local license file will be created on the device. However, the license will still appear as "active" in the LicenseSpring portal because the server cannot verify the device's state in an air-gapped environment.

To prevent losing a license due to such errors, we recommend:

- Saving the **QR code** or JSON data provided during the confirmation step. This allows users to re-enter the correct data in the client application if the first attempt fails.
- Double-checking all inputs (license key, policy file path, activation code) before proceeding with the activation process in the SDK.
:::

![Final Pop-Up Confirming Activation](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/H3HlOOUqWeagxys6VFX9e_image.png "Final Pop-Up Confirming Activation")

Enter this information into the client application, and the activation process should be complete!

:::hint{type="info"}
Airgap deactivation follows the same flow, you just need to toggle the initial view to Deactivation.
:::

![Airgap Deactivation](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/2oU2gnbPwN1NpnLs8S5ZU_scr-20230809-mcrg.png "Airgap Deactivation")

## Frequently Asked Questions

**1. What happens if the activation process fails on the end device?**

- If an air-gapped license activation fails on the device (e.g., due to an incorrect policyFilePath or confirmation code), the SDK will throw an error, and no local license file will be created. However, the license will still appear as "active" in the LicenseSpring portal. This behavior is due to the offline nature of the device and the inability of the server to validate the device's state. Ensure all inputs are correct before submitting the activation request.

**2. Can I reset or reuse a license that failed to activate locally?**

- Currently, licenses marked as "active" in the LicenseSpring portal cannot be reactivated unless they are deactivated first. For this reason, it is critical to safeguard the JSON data or QR code provided during the activation process so you can re-enter it into the client application if an error occurs.


[title] License Start Date
[path] License Entitlements/

When issuing a license, you can set a start date for it. Adding a start date to a license will not allow license activations for until that date. This can be useful to fine-tune usage of a rented or time-limited license, or to make a software available only for an academic term, for example.

## Issuing Licenses With a Start Date

Navigate to the product selection screen during the process of issuing licenses. Toggle the "Use custom license values". Under license usage, there is a field called "License Start Date" where you can specify the start date.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/B0cp7IFFtLQvmWbH_Cm4j_image.png)

## Add/Modify/Remove the Start Date of an Existing License

:::hint{type="info"}
If you set a start date on an existing license that had already been activated, it will not affect the license that has already activated it. Instead, it will simply prevent additional license activations until the start date.
:::

Navigate to the license detail screen and press "Edit License". From there you can set or delete the "License Start Date".



![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/LszV-b4o_jHvMLbn7Y0wb_image.png "Editing License")

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/83mXCRCk6pgE1EGw8JNdE_image.png "Editing License Start Date")


[title] License Types
[path] License Entitlements/

One of the fundamental building blocks of a license within our model is the license type. Every license issued will always have a type. In the vendor platform, this appears in many places, such as the license summary page as well as on the license detail page.&#x20;

![License Type Appearing on the License Detail Screen](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/6KvGueQ2WyVXfzZ9uy9Wt_image.png "License Type Appearing on the License Detail Screen")

:::hint{type="danger"}
You cannot change the **license type&#x20;**&#x6F;nce it has been created.
:::

LicenseSpring defines 4 types of licenses:&#x20;

- Perpetual
- Time-Limited
- Subscription
- Consumption

Let's dive into the different license types:

## Perpetual License

A perpetual license does not expire. The `is_expired`  field on a license check will always return `False` .

:::hint{type="warning"}
At the time of this writing, we distinguish a `trial license` through a Boolean value `isTrial` . If a license is of type trial, then the date stored in the validity period refers to the validity period of the trial. For example, if the license is of type `perpetual`, and `isTrial`  is true, you would see a perpetual license with an expiry date in the vendor platform.
:::

### Statuses of a Perpetual License

- `Inactive` The `times_activated`  for this given license is `0` , meaning that this license has not been bound to a device.
- `Active` The `times_activated`  for this field is greater than `0` , meaning that the license has been bound to at least one device.&#x20;
- `Disabled` The license has been disabled by the vendor, this will override other rules for this status.

## Time-Limited License

Time-limited licenses always have a calendar date as a value in the `Expiry date`  row that you can see in the vendor platform.&#x20;

On a license check, the field `is_expired`  will be `True` if the expiry date is earlier than the server's current date, and `False`  if the expiry date of the license is at a future date than the server's timestamp.

### Status of a Time-Limited License

- `Inactive` The `Total Activations`  for this given license is `0` , meaning that this license has not been bound to a device.
- `Active` The `Total Activations`  for this field is greater than `0` , meaning that the license has been bound to at least one device.&#x20;
- `Disabled` The license has been disabled by the vendor, this will override other rules for this status.

:::hint{type="info"}
There are other timestamps you can work with, instead of just at the license type level. For instance, you can set an expiry date for a specific feature, or define a maintenance period validity.
:::

### Setting a Pre-Determined Expiration Date

Users can set a pre-determined expiration date for a license that does not depend on the time of first activation by doing the following at time of issuance:

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/HJ2u0tUGl_dRD3PQBREK4_image.png" signedSrc size="62" width="477" height="335" position="center" caption}

## Subscription License

A subscription license synchronizes the status of the subscription with the state of the license.

:::hint{type="info"}
For a subscription license, LicenseSpring requires an integration to an external source of truth (like a recurring billing system). LicenseSpring updates the status of the license according to the status of the subscription, which is handled by a 3rd party. &#x20;
:::

:::hint{type="warning"}
Unlike the other license types you can encounter in LicenseSpring, the status is not dependent on the value of the `times_activated` field. Instead, a license of type subscription will be `active` once created, and will remain active until the system handling the subscription tells LicenseSpring that the subscription is no longer active (cancelled, refunded, etc). In this case, the license status will be set to `inactive`&#x20;
:::

### Subscription Grace Period

Grace periods offer you the flexibility to determine a specific timeframe, measured in hours, subsequent to the expiry of the designated validity period.&#x20;

During this defined interval, the license will retain its validity (`isExpired()` status will remain false), ensuring a seamless transition even after the official expiration.

### Status of a Subscription License

- `Inactive` LicenseSpring received information from the external source of truth stating that the subscription is no longer active.
- `Active` This is the default state of a subscription license, when it is created.
- `Disabled` The license has been disabled by the vendor, this will override other rules for this status.

## Consumption License

A consumption license, also known as a metered license, permits usage metering. consumption licenses work by setting a value the the resource the vendor wishes to meter, and then recording the times that resource has been used. The resource can really be anything that has a discrete value, for example:&#x20;

- Times the software was run
- The number of API requests made
- Number in minutes that a pooled resource was used
- Credit

Consumption licenses support overages, total consumptions can be incremented or decremented (by adding a negative value), and the total consumptions can be periodically reset.

::Image[]{alt="Options available when issuing a consumption-based license" src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/KFQvA854MZuUeIWetdc4b_image.png" size="54" width="370" height="465" caption="Options available when issuing a consumption-based license" position="flex-start" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/KFQvA854MZuUeIWetdc4b_image.png"}

### Unique Fields in a Consumption License

![Unique fields for a consumption license](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/bYd4H5Zza7KZB2z_teMqk_image.png "Unique fields for a consumption license")

- **Max Consumptions**: Number of "consumptions" granted to the end user.
- **Total Consumptions**: Number of "consumptions" the end-user has currently consumed. This number must be less than or equal to the max consumptions + max overages.
- **Overages**: If overages are allowed, then the software vendor can specify a value that the license can exceed the value for max consumptions by. Otherwise, the max overages is 0.
- **Consumption Period**: If this field is set, then the value for total consumptions is reset to 0. The consumption period can be `Daily`, `Weekly`, `Monthly` or `Annually`
  - `Daily`  is reset at midnight UTC
  - `Weekly`  is reset on Monday at midnight UTC
  - `Monthly`  is reset on the first day of the month at midnight UTC
  - `Annually`  is reset on the first day of the year at midnight UTC

### Status of a Consumption License

- `Inactive` : The `Total Activations`  for this given license is `0` , meaning that this license has not been bound to a device.
- `Active` : the `Total Activations`  for this field is greater than `0` , meaning that the license has been bound to at least one device.&#x20;
- `Disabled` : The license has been disabled by the vendor, this will override other rules for this status.

:::hint{type="info"}
LicenseSpring also allows an ISV to meter the usage of an individual module or component by defining features consumptions, and adding them as part of the license entitlements.
:::





##




[title] Hardware Key Licensing
[path] License Entitlements/License Activation Types/

In the LicenseSpring platform, users can generate and customize licenses to require a hardware key. LicenseSpring supports using [**YubiKey**](https://www.yubico.com/) hardware keys.

:::hint{type="warning"}
Hardware Key Licensing is an add-on functionality in Licensespring. Contact sales to enable it on your account.
:::

These licenses can only be activated and used only when hardware key is plugged-in. To start using hardware key licensing you need to:

1. Create hardware key required licenses
2. Provision hardware keys so that they can be used with LicenseSpring service

## Create hardware key required licenses

### Issue License from LicenseSpring

- Configure license entitlements (max concurrent users, features, validity period etc.)
- Ensure `Require Hardware Key` is Ticked

![Configure license entitlements](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/tfqo4g5ZC3Hw46uHAEP5G_require-hardware-key.png "Configure license entitlements")

Click Next and Create Order.

![Create order](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/NVkevfRqc83rYEYszUC51_scr-20240517-mndx.png "Create order")

## Provision hardware keys&#x20;

### Desktop application installer

Download and install the **LicenseSpring Provisioning Application for Desktop** from [**here**](https://ls-provisioner.s3.eu-west-1.amazonaws.com/index.html).&#x20;

:::hint{type="warning"}
We currently support x64 Windows, but we will expand the support for the rest of the OS environments.
:::

This application will handle all the provisioning logic. It will create certificate and private and public keys for Yubikey dongle. Private key will be saved in the Yubikey, and public key will be kept in LicenseSpring and used for signature verification.

Install the [**MSVC redistributable**](https://aka.ms/vs/17/release/vc_redist.x64.exe) if it is not available already.

### Key certificate provisioning

Visit the `Hardware Keys` page in LicenseSpring vendor platform ( Licenses -> Hardware Keys ). Here you can see the list of all provisioned hardware keys for your account and informations like expiration date of the certificate, is the certificate revoked or active and if it is already used to activate a license. If it is, button `View license` will be displayed in table row.

![Hardware Keys](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/tHZ93EtBfu13RlqIb0VGp_scr-20240517-moks.png "Hardware Keys")

To provision a new key certificate, click on `Provision the key certificate` button and confirm the action inside the popup. This will redirect you to the desktop application which you installed in previous step. This application will start the provisioning process in the background.

If the process is successful, you should get a message window stating `Succeeded writing cert` and new certificate will be saved in PIV slot 9a. Otherwise, you will get a message window with some kind of error and writing the certificate will fail.

:::hint{type="warning"}
Provisioning will overwrite the RSA2048 keypair in PIV slot 9a.
:::

Once this is done, you can safely activate the license using the hardware key. The hardware key must remain plugged in at all times while the software is running, otherwise the license will not function.


[title] Trial Licenses
[path] License Entitlements/

All licenses have a Boolean field denoting whether it is a trial or not. This can be seen on the license summary as well as the license detail page:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/z5JscyytIaQ-D7zCx6Rcs_image.png)

:::hint{type="info"}
By using the `is_trial` Boolean designating a license is of type trial, you have a flag that allows you to configure your software in demo mode.
:::

## Particularities of a Trial License

- Trial licenses are the only type of license that can be issued through the License API. In other words, your application can request and activate a trial license without the software vendor's involvement.
- By changing the Boolean value of the `is_trial`  field from `True`  to `False` , you can upgrade a license.
- Since any license type can also be a trial license, you might notice that a perpetual or a consumption license can also have an expiry date.

:::hint{type="info"}
When a license is a trial license, the expiry date for that license always refers to the trial expiry date.
:::

## Setting a Trial Expiration Date Through the Vendor Platform

You can either set a fixed end date, or a set number of days from the first use of the trial license:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/rETnqLLdWcKKYVdDZz5c__image.png)

Before activation you have two options - you can either set `trial_days` **OR** `validity_period` on a trial license. If both are defined on a trial license, when this license is activated, **validity\_period will take precedence** and License API will use this field and ignore trial\_days. If only trial\_days are defined, then validity\_period will be calculated and used to determine license validity.

Use only `trial_days` if you want the validity\_period to be calculated on the time of activation based on this number

Use `validity_period` if you already know, even before activation, until when this license should be valid.

## “Upgrading” a Trial License

Any trial license can be edited to modify the license so that it is no longer a trial license, but a full license for your product. To do so:

1. Open the license detail page for that given trial license and Click "Edit License"&#x20;
2. Uncheck the "Is Trial" box, and click "Save"



![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/URrJzlRide6RYLvbPnC-m_image.png "Editing From Trial to Full License")

## Issuing New Trial Licenses

There are a few ways that a trial license can be issued:

- Through the vendor platform on [**Issuing New Licenses**](docId\:fedDg9WixsYbHadHXYoL0) view
- Through the License API using [**Trial Key**](docId\:MtAnOsFYJyXU-2M0OVz_a) endpoint
- Through the Management API using [**Create Order**](docId\:GCoYGuLOy0Np_x03DVcK2) endpoint


[title] Cloud Concurrent Licensing
[path] License Entitlements/Floating Licenses/

With LicenseSpring, application developers can allocate licenses for simultaneous usage, wherein LicenseSpring functions as the floating license server.

![LicenseSpring Floating Cloud Visualization ](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/EPAhDhHvl54itpVw_2eZq_image.png "LicenseSpring Floating Cloud Visualization ")

## Configuring Floating Cloud Licenses

Configuring a cloud-based floating license involves adjusting several parameters:

### Timeout Period

Within the process of setting up a new product, you'll encounter a parameter named "floating timeout."&#x20;

This value, measured **in minutes**, dictates how frequently the license application must communicate with the LicenseSpring server to maintain the license's active state.&#x20;

Should the application fail to establish contact with the server before the designated timeout duration elapses, the license will be automatically freed from that particular application.

If you wish to modify the Floating timeout duration for an already-configured product, follow these steps: Access the product > Choose "Edit Product" > Navigate to "License Configuration."

:::hint{type="info"}
**Note:&#x20;**&#x54;he floating timeout period is defined at the product level, but you can overide it per license policy or on the license itself.&#x20;
:::

![Initial product configuration allows you to set the floating timeout.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/gEyOA3W7ZK5Jb6OAfL3gi_scr-20230809-lsvj.png "Initial product configuration allows you to set the floating timeout.")

![Set floating timeout on license policy](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/3M-JarL3wFhsBaLF_KIRR_scr-20230809-ltcv.png "Set floating timeout on license policy")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/_k9VCT8sVyamxUxNnIP56_scr-20230809-lscw.png)

### Max Simultaneous License Users

During the setup of a new product license policy, if the chosen license type is a floating cloud license, you will specify the quantity of devices that can simultaneously utilize the license.

Additionally, it's possible to designate the number of concurrent users at the time of license issuance, and this allocation can be modified subsequently, even after the license has already been granted.

:::hint{type="info"}
**Note:&#x20;**&#x4D;ax simultaneous users is **not the same** as max activations. Simultaneous users are the total number of machines that can concurrently use a license, while max activations are the number of machines that are node locked to the license.

**A license must have been activated on a device before the device can check it out.**

Simultaneous users should therefore be less than or equal to max activations, if max activations are not set to unlimited.
:::

![Setting the default max concurrent usage.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/68x2xYspxsz5lU2Blsi01_scr-20230809-lugq.png "Setting the default max concurrent usage.")

![Changing the default max simultaneous license users value.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/SvWJgf5s7a0f3uHW-v90-_scr-20230809-luon.png "Changing the default max simultaneous license users value.")

The usage of these licenses is similar to that of normal licenses. You utilize `activate_license`, `check_license` and other endpoints as usual. The SDK handles the other aspects such as checking for concurrent usage.

After a license is activated, it needs to be checked to occupy a floating slot.

### Release

Floating license can be released using: API, Platform and License Manager

**API**

A call should be made to `/api/v4/floating/release` to gracefully release the license floating slot. This call will avoid waiting for the timeout to release the license.

See [**Release Floating License**](docId\:Ac4QjdmMGxWJRZJv9mRrU) for more information on how to release a floating license via our API.

**Platform**

To Release License inside platform go to: License --> Devices --> Chose device --> Actions --> Revoke

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/gSvhRhCeYehzdP2coUCb1_image.png)


[title] Consumption Period in License/Features
[path] License Entitlements/

- **Consumption Period**: If this field is set, then the value for total consumptions is reset to 0. The consumption period can be `Daily`, `Weekly`, `Monthly` or `Annually`
  - `Daily`  is reset at midnight UTC
  - `Weekly`  is reset on Monday at midnight UTC
  - `Monthly`  is reset on the first day of the month at midnight UTC
  - `Annually`  is reset on the first day of the year at midnight UTC


[title] Air-Gapped Portal
[path] Portals/

The air-gapped license portal can be found at:

URL: [**airgap.licensespring.com**](https://airgap.licensespring.com)

For instructions on how activate licenses using the air-gapped portal, please find the article on the [**Air-Gapped License Activation**](docId\:UFo9u_RePM5NOV_0qBySZ) .

[title] Deactivate License (Online Method)
[path] License API/License Activation/Deactivation/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/deactivate_license",
  "name": "/api/v4/deactivate_license",
  "method": "POST",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "String",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "kind": "optional",
        "name": "license_key",
        "type": "string",
        "children": [],
        "description": "Required if product is key-based (see section below)"
      },
      {
        "kind": "optional",
        "name": "username",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "kind": "optional",
        "name": "id_token",
        "type": "string",
        "children": [],
        "description": "Required if using SSO (see section below). This is the id_token received from the SSO if Implicit grant authorization method is being used."
      },
      {
        "kind": "optional",
        "name": "code",
        "type": "string",
        "children": [],
        "description": "Required if using SSO (see section below). This is the code received from the SSO if Authorization code grant method is being used."
      },
      {
        "kind": "optional",
        "name": "customer_account_code",
        "type": "string",
        "children": [],
        "description": "Required if using SSO (see section below). This is the customer_account_code to which SSO provider is configured. "
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "Number",
        "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "children": []
      },
      {
        "kind": "optional",
        "name": "sdk_ver",
        "type": "string",
        "description": "Version of the SDK used",
        "": "Version of the SDK used"
      },
      {
        "name": "consumptions",
        "kind": "optional",
        "type": "number",
        "description": "Increases/decreases total_consumptions",
        "": "Increases/decreases total_consumptions"
      }
    ],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "es8g1cuKJMbNPiIVt9VoF",
        "code": "license_deactivated",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "7eyIlKSv2QgJcowEsDZ-2",
        "code": "{\n    \"unknown_product\": \"Provided product was not found\",\n    \"license_not_found\": \"License with the provided license user not found\",\n    \"license_not_enabled\": \"The license is not enabled\",\n    \"vm_not_allowed\": \"Virtual machine not allowed\",\n    \"offline_floating_cloud_not_supported\": \" Floating cloud licenses cannot be activated offline.\",\n    \"license_start_date_error\": \"This license cannot be activated before start date: {date}\",\n    \"blacklisted\": \"This device is blacklisted\",\n    \"license_activated_max_times\": \"This license  has already been activated the maximum number of times\",\n    \"license_user_activated_max_times\": \"License user has activated this license max times\",\n    \"license_expired\": \"License validity period has expired.\",\n    \"license_transferred_max_times\": \"This license has already been transferred the maximum number of times\",\n    \"license_device_exists\": \"A device matching this hardware_id is already created on the license\"\n}",
        "language": "400",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "7eyIlKSv2QgJcowEsDZ-2"
  },
  "examples": {
    "languages": [
      {
        "id": "xgX5uw4vq7BJNbqvQ_ia0",
        "language": "curl",
        "code": "curl --location --request POST '/api/v4/deactivate_license' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string' \\\n--data-raw '{\"hardware_id\":\"String\",\"product\":\"string\",\"license_key\":\"string\",\"username\":\"string\",\"password\":\"string\",\"id_token\":\"string\",\"code\":\"string\",\"customer_account_code\":\"string\",\"is_vm\":\"Boolean\",\"vm_info\":\"string\",\"os_ver\":\"string\",\"hostname\":\"string\",\"os_hostname\":\"string\",\"ip\":\"string\",\"ip_local\":\"string\",\"app_ver\":\"string\",\"sdk_ver\":\"string\",\"mac_address\":\"string\"}'",
        "customLabel": ""
      },
      {
        "id": "3Fz0Q_qaZA0RnhG5k5R_W",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'POST',\n   'url': '/api/v4/deactivate_license',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   },\n   body: '{\"hardware_id\":\"String\",\"product\":\"string\",\"license_key\":\"string\",\"username\":\"string\",\"password\":\"string\",\"id_token\":\"string\",\"code\":\"string\",\"customer_account_code\":\"string\",\"is_vm\":\"Boolean\",\"vm_info\":\"string\",\"os_ver\":\"string\",\"hostname\":\"string\",\"os_hostname\":\"string\",\"ip\":\"string\",\"ip_local\":\"string\",\"app_ver\":\"string\",\"sdk_ver\":\"string\",\"mac_address\":\"string\"}'\n\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "uJvCS-wF1cAIBTUqKJTug",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar raw = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"password\\\":\\\"string\\\",\\\"id_token\\\":\\\"string\\\",\\\"code\\\":\\\"string\\\",\\\"customer_account_code\\\":\\\"string\\\",\\\"is_vm\\\":\\\"Boolean\\\",\\\"vm_info\\\":\\\"string\\\",\\\"os_ver\\\":\\\"string\\\",\\\"hostname\\\":\\\"string\\\",\\\"os_hostname\\\":\\\"string\\\",\\\"ip\\\":\\\"string\\\",\\\"ip_local\\\":\\\"string\\\",\\\"app_ver\\\":\\\"string\\\",\\\"sdk_ver\\\":\\\"string\\\",\\\"mac_address\\\":\\\"string\\\"}\";\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/deactivate_license\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "oHvG2_KC9rAafj9m1qUOF",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/deactivate_license\"\n\npayload = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"password\\\":\\\"string\\\",\\\"id_token\\\":\\\"string\\\",\\\"code\\\":\\\"string\\\",\\\"customer_account_code\\\":\\\"string\\\",\\\"is_vm\\\":\\\"Boolean\\\",\\\"vm_info\\\":\\\"string\\\",\\\"os_ver\\\":\\\"string\\\",\\\"hostname\\\":\\\"string\\\",\\\"os_hostname\\\":\\\"string\\\",\\\"ip\\\":\\\"string\\\",\\\"ip_local\\\":\\\"string\\\",\\\"app_ver\\\":\\\"string\\\",\\\"sdk_ver\\\":\\\"string\\\",\\\"mac_address\\\":\\\"string\\\"}\"\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "urxE_DgGNxfjEo27HuGSl",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/deactivate_license\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\nrequest.body = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"password\\\":\\\"string\\\",\\\"id_token\\\":\\\"string\\\",\\\"code\\\":\\\"string\\\",\\\"customer_account_code\\\":\\\"string\\\",\\\"is_vm\\\":\\\"Boolean\\\",\\\"vm_info\\\":\\\"string\\\",\\\"os_ver\\\":\\\"string\\\",\\\"hostname\\\":\\\"string\\\",\\\"os_hostname\\\":\\\"string\\\",\\\"ip\\\":\\\"string\\\",\\\"ip_local\\\":\\\"string\\\",\\\"app_ver\\\":\\\"string\\\",\\\"sdk_ver\\\":\\\"string\\\",\\\"mac_address\\\":\\\"string\\\"}\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "uJvCS-wF1cAIBTUqKJTug"
  },
  "description": "Dectivate a license for a product\n",
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4deactivatelicense",
  "legacyHash": "nfu_UCHm2-CiBeU98AfrR"
}
```
:::

## Schema

### Request Body

:::CodeblockTabs
```typescript
type LicenseActivationRequestBody = ({

  // for key-based licenses:
  license_key: string

} | {

  // for user-based licenses:
  username: string
  password: string

} | {

  // for user-based licenses using single sign-on Implicit grant:
  id_token: string
  customer_account_code: string

} | {

  // for user-based licenses using single sign-on Authorization code grant:
  code: string
  customer_account_code: string

}) & {

  // required properties:
  hardware_id: string
  product: string

  // optional properties:
  bundle_code?: string | undefined
  license_id?: number | undefined
  sdk_ver?: string | undefined
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "allOf": [
    {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "license_key": { "type": "string" }
          },
          "required": ["license_key"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "username": { "type": "string" },
            "password": { "type": "string" }
          },
          "required": ["username", "password"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "id_token": { "type": "string" },
            "customer_account_code": { "type": "string" }
          },
          "required": ["id_token", "code", "customer_account_code"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "code": { "type": "string" },
            "customer_account_code": { "type": "string" }
          },
          "required": ["id_token", "code", "customer_account_code"],
          "additionalProperties": false
        }
      ]
    },
    {
      "type": "object",
      "properties": {
        "hardware_id": { "type": "string" },
        "product": { "type": "string" },
        "bundle_code": { "type": "string" },
        "license_id": { "type": "number" },
        "sdk_ver": { "type": "string" }
      },
      "required": ["hardware_id", "product"],
      "additionalProperties": false
    }
  ]
}
```
:::

### Response Body

If the request succeeds, the endpoint responds with the HTTP code 200 and the string `license_deactivated`.

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

### Key-based product licenses

Each license assigned to the product requires the client to provide a license key in order to activate, check or deactivate the license (property `license_key` in the request body).

The license response object will contain the `license_key` property, and the property `product_details.authorization_method` will be the string `license_key`.

### User-based product licenses

Each license assigned to the product has a corresponding "license user" instead of a license key. There are multiple ways a user-based product license can be accessed when making a request:

- By providing the values for `username` and `password` for the license user
- By providing the values for `id_token` and `customer_account_code` if using single sign-on authentication using Implicit grant
- By providing the values for `code` and `customer_account_code` if using single sign-on authentication using Authorization code grant



In the license response object, `product_details.authorization_method` will have the string value `user` and the response object will contain the `user` object with information on the license user.&#x20;

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of Exceptions

:::BlockQuote
**unknown\_product&#x20;**(400): Provided product was not found
:::

:::BlockQuote
**license\_not\_found** (400): License with the provided license user not found
:::

:::BlockQuote
**license\_not\_active&#x20;**(400): The license is not active
:::

:::BlockQuote
**device\_not\_found** (400): An active device matching the hardware\_id not found
:::

:::BlockQuote
**missing\_headers&#x20;**(400): Some headers are missing
:::

###


[title] Request Signature
[path] License API/License API Authorization/

## Overview

Requests sent to the server have to be digitally signed for purposes of authentication. The signature uses the Date header anxd signing algorithm used in [**License API Authorization**](docId:4pkAMPCtiBGTUMMvTwCY3).

## Signature Structure

The **signature** in the **Authorization** header is a **Base64-encoded HMAC-hashed** value of the signing string, which is composed of:

1. A constant string: `licenseSpring`
2. A newline character `\n`
3. The value of the Date header being sent in the request (see [**License API Authorization**](docId:4pkAMPCtiBGTUMMvTwCY3) for more details). This is a date string in [**RFC7231**](https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.1.1) format

This signing string is then hashed with the customer's key (shared key) using the algorithm provided in the Authorization header (e.g. **HMAC-SHA256**). The resulting hash is then encoded in **Base64**.

:::hint{type="info"}
Make sure the encoded string has no extra whitespace on any line, otherwise the base64 encoded value will be incorrect.
:::

## Example of Signature Generation

The following is an example of how to generate a signature. First, let's assume the following values:

- Your company's **shared key&#x20;**&#x69;s `kw4qSnpSwXzgiv5yxYpZZmFEd9QAeiKTQ6OuyMja`
- The Date header you set in the request is `Tue, 07 Jun 2011 20:51:35 GMT`
- We'll use the default hashing algorithm, HMAC-SHA256

Now we can generate the signature:

**1.** Create the signing string:

```none
licenseSpring
date: Tue, 07 Jun 2011 20:51:35 GMT
```

**2.** Hash the signing string using HMAC-SHA256

**3.** Encode the hashed value with Base64: `UDysfR6MndUZReo07Y9r+vErn8vSxrnQ5ulit18iJ/Q=`

The resulting string is then inserted into the **Authorization&#x20;**&#x68;eader as the "signature" parameter:

```none
algorithm="hmac-sha256", headers="date", signature="UDysfR6MndUZReo07Y9r+vErn8vSxrnQ5ulit18iJ/Q=", apikey="_company_api_key_here_"
```

## Sample Code

Generating a **signature**

:::CodeblockTabs
```javascript
const crypto = require('node:crypto'),
    shared_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    signing_string = 'licenseSpring\ndate: Tue, 07 Jun 2011 20:51:35 GMT';

let signature = crypto.createHmac('sha256', shared_key).update(signing_string).digest('base64');

console.log(signature);
// UDysfR6MndUZReo07Y9r+vErn8vSxrnQ5ulit18iJ/Q=
```

```python
import base64
import hashlib
import hmac
import time
from wsgiref.handlers import format_date_time

# Can be found in `Account Settings` -> `Settings` -> `Keys`
shared_key = '_your_shared_key_goes_here_'

def sign(secret_key, datestamp):
    msg = 'licenseSpring\ndate: %s' % datestamp
    hashed = hmac.new(bytes(secret_key, 'utf-8'), msg.encode('utf-8'), hashlib.sha256).digest()
    return base64.b64encode(hashed).decode()

# Generate headers
date_header = format_date_time(time.time())

signing_key = sign(shared_key, date_header)
```
:::

Generating ful&#x6C;**&#x20;HTTP** **request headers** with SDK Demo keys

:::CodeblockTabs
```javascript
const fetch = require('node-fetch');

const sharedKey = 'XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX',
      apiKey = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
      productCode = "XX",
      baseURL = 'https://api.licensespring.com/api/v4/webhook';

function GenerateHeaders(){
    const signingDate = (new Date()).toUTCString(),
          signingString = `licenseSpring\ndate: ${signingDate}`;

    const signature = crypto.createHmac('sha256', sharedKey).update(signingString).digest('base64');

    return {
            'Content-Type': 'application/json',
            'Date': signingDate,
            'Authorization' : `algorithm="hmac-sha256",headers="date",signature="${signature}",apikey="${apiKey}"`,
        };
}
```

```python
import base64
import hashlib
import hmac
import time
from wsgiref.handlers import format_date_time

# Can be found in `Account Settings` -> `Settings` -> `Keys`
shared_key = '_your_shared_key_goes_here_'
uuid = '_your_uuid_key_goes_here_'

def sign(secret_key, datestamp):
    msg = 'licenseSpring\ndate: %s' % datestamp
    hashed = hmac.new(bytes(secret_key, 'utf-8'), msg.encode('utf-8'), hashlib.sha256).digest()
    return base64.b64encode(hashed).decode()

# Generating headers
date_header = format_date_time(time.time())

signing_key = sign(shared_key, date_header)

auth_header = ','.join([
    'algorithm="hmac-sha256"',
    'headers="date"',
    'signature="%s"' % signing_key,
    'apiKey="%s"' % uuid
])

headers = {
  'Date': date_header,
  'Authorization': auth_header
}
```
:::

Full sample code for checking a license key with SDK Demo keys

:::CodeblockTabs
```javascript
const fetch = require('node-fetch');

const sharedKey = 'XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX',
      apiKey = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
      productCode = "XX",
      baseURL = 'https://api.licensespring.com/api/v4';

function GenerateHeaders(){
    const signingDate = (new Date()).toUTCString(),
          signingString = `licenseSpring\ndate: ${signingDate}`;

    const signature = crypto.createHmac('sha256', sharedKey).update(signingString).digest('base64');

    return {
            'Content-Type': 'application/json',
            'Date': signingDate,
            'Authorization' : `algorithm="hmac-sha256",headers="date",signature="${signature}",apikey="${apiKey}"`,
        };
}

const checkLicense = async (hwid, licenseKey) => {
    const headers = GenerateHeaders()

    const response = await fetch(baseURL + '/check_license' + `?product=${productCode}&hardware_id=${hwid}&license_key=${licenseKey}`, {
        method: 'GET',
        headers: headers
    })
    console.log("/license response", await response.json());
}

checkLicense('d32q3ed3rq3rxq2r3q23q23q23', '1111-2222-3333-4444');
```

```python
import base64
import hashlib
import hmac
import time
from wsgiref.handlers import format_date_time

import requests

API_URL = 'https://api.licensespring.com'

# Can be found in `Account Settings` -> `Settings` -> `Keys`
shared_key = '_your_shared_key_goes_here_'
uuid = '_your_uuid_key_goes_here_'

def sign(secret_key, datestamp):
    msg = 'licenseSpring\ndate: %s' % datestamp
    hashed = hmac.new(bytes(secret_key, 'utf-8'), msg.encode('utf-8'), hashlib.sha256).digest()
    return base64.b64encode(hashed).decode()

# Generate headers
date_header = format_date_time(time.time())

signing_key = sign(shared_key, date_header)

auth_header = ','.join([
    'algorithm="hmac-sha256"',
    'headers="date"',
    'signature="%s"' % signing_key,
    'apiKey="%s"' % uuid
])

# Send request
product_short_code = '_your_product_short_code_goes_here_'
hardware_id = '_your_hardware_id_goes_here_'
license_key = '_your_license_key_goes_here_'

response = requests.get(
    url='{}{}'.format(API_URL, '/api/v4/check_license/'),
    params={'product': product_short_code, 'hardware_id': hardware_id, 'license_key': license_key},
    headers={
        'Date': date_header,
        'Authorization': auth_header,
        'Content-Type': 'application/json'
    }
)

print(response.json())
```
:::


[title] License Feature Check
[path] License API/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "  /api/v4/check_license_feature",
  "name": "  /api/v4/check_license_feature",
  "method": "GET",
  "request": {
    "pathParameters": [],
    "queryParameters": [
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "string",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "name": "feature",
        "kind": "required",
        "type": "string",
        "description": "Feature code",
        "children": []
      },
      {
        "kind": "optional",
        "name": "license_key",
        "type": "string",
        "children": [],
        "description": "Required if product is key-based (see section below)"
      },
      {
        "kind": "optional",
        "name": "username",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "Number",
        "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "children": []
      }
    ],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "QLX3IFr3FPKeqNnhkuAXk",
        "code": "{\n    \"id\": 1698664358119314,\n    \"code\": \"f0\",\n    \"name\": \"f0\",\n    \"feature_type\": \"activation\",\n    \"expiry_date\": null,\n    \"metadata\": {},\n    \"is_floating\": false,\n    \"is_floating_cloud\": true,\n    \"floating_timeout\": 120,\n    \"floating_users\": 8,\n    \"floating_in_use_devices\": 1,\n    \"license_id\": 1698662161371339\n}",
        "language": "200",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "QLX3IFr3FPKeqNnhkuAXk"
  },
  "examples": {
    "languages": [
      {
        "id": "Lhd_uaIV7Ofbyvv2llLuw",
        "language": "curl",
        "code": "curl --location --request GET '/api/v4/check_license_feature?hardware_id=string&product=string&feature=string' \\\n--header 'Accept: application/json' \\\n--header 'Content-Type: application/json'",
        "customLabel": ""
      },
      {
        "id": "wZw1bjDViqlggtv4TmCzd",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'GET',\n   'url': '/api/v4/check_license_feature?hardware_id=string&product=string&feature=string',\n   'headers': {\n      'Accept': 'application/json',\n      'Content-Type': 'application/json'\n   }\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "ptIbgbAyC3qU8ZeFYfTPs",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Content-Type\", \"application/json\");\n\nvar requestOptions = {\n   method: 'GET',\n   headers: myHeaders,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/check_license_feature?hardware_id=string&product=string&feature=string\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "KObJoQpaIfQA2b0GcaqRg",
        "language": "python",
        "code": "import requests\nimport json\n\nurl = \"/api/v4/check_license_feature?hardware_id=string&product=string&feature=string\"\n\npayload={}\nheaders = {\n   'Accept': 'application/json',\n   'Content-Type': 'application/json'\n}\n\nresponse = requests.request(\"GET\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "TEyWqegGMGJqtmeopJpyL",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"json\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/check_license_feature?hardware_id=string&product=string&feature=string\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Content-Type\"] = \"application/json\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "Lhd_uaIV7Ofbyvv2llLuw"
  },
  "description": "Checks a license device against a license feature. Once checked, this device will be connected to the feature. If a feature is a floating feature, device will also take one floating slot if available.\n",
  "currentNewParameter": {
    "label": "Query Parameter",
    "value": "queryParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "apiv4checklicensefeature",
  "legacyHash": "6TY_-XG04aw-vgfUVo06E"
}
```
:::

## Schema

### Request Query Parameters

:::CodeblockTabs
```typescript
type LicenseFeatureCheckRequestParams = ({

  // for key-based licenses:
  license_key: string

} | {

  // for user-based licenses:
  username: string

}) & {

  // required properties:
  hardware_id: string
  product: string
  feature: string

  // optional properties:
  license_id?: number | undefined
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "allOf": [
    {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "license_key": { "type": "string" }
          },
          "required": ["license_key"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "username": { "type": "string" }
          },
          "required": ["username"],
          "additionalProperties": false
        }
      ]
    },
    {
      "type": "object",
      "properties": {
        "hardware_id": { "type": "string" },
        "product": { "type": "string" },
        "feature": { "type": "string" },
        "license_id": { "type": ["number", "null"] }
      },
      "required": ["hardware_id", "product", "feature"],
      "additionalProperties": false
    }
  ]
}
```
:::

### Response Body

:::CodeblockTabs
```typescript
type LicenseFeatureCheckResponseBody = {
    allow_negative_consumptions: boolean,
    allow_overages: boolean,
    allow_unlimited_consumptions: boolean,
    code: string,
    consumption_period: string,
    expiry_date: null | string,
    feature_type: string,
    id: number,
    is_floating_cloud: boolean,
    is_floating: boolean,
    license_id: number,
    max_consumption: number,
    max_overages: number,
    metadata: JSON,
    name: string,
    reset_consumption: boolean,
    total_consumptions: number,
    can_borrow: boolean,
    max_borrow_time: number,
    
    // the following property is only present on floating and floating cloud features:
    floating_in_use_devices?: number,
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "allow_negative_consumptions": { "type": "boolean" },
    "allow_overages": { "type": "boolean" },
    "allow_unlimited_consumptions": { "type": "boolean" },
    "code": { "type": "string" },
    "consumption_period": { "type": "string" },
    "expiry_date": { "type": ["string", "null"] },
    "feature_type": { "type": "string" },
    "id": { "type": "number" },
    "is_floating_cloud": { "type": "boolean" },
    "is_floating": { "type": "boolean" },
    "license_id": { "type": "number" },
    "max_consumption": { "type": "number" },
    "max_overages": { "type": "number" },
    "metadata": { "type": "object" },
    "name": { "type": "string" },
    "reset_consumption": { "type": "boolean" },
    "total_consumptions": { "type": "number" },
    "floating_in_use_devices": { "type": "number" },
    "max_borrow_time": { "type": "number" },
    "can_borrow": { "type": "boolean" }
  },
  "required": [
    "allow_negative_consumptions",
    "allow_overages",
    "allow_unlimited_consumptions",
    "code",
    "consumption_period",
    "expiry_date",
    "feature_type",
    "id",
    "is_floating_cloud",
    "is_floating",
    "license_id",
    "max_consumption",
    "max_overages",
    "metadata",
    "name",
    "reset_consumption",
    "total_consumptions"
  ],
  "additionalProperties": false
}
```
:::

Response contains a license feature fields :

**floating\_in\_use\_devices&#x20;**- number of devices currenly in use on this license feature **license\_id** - id of the license

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**missing\_headers** (400): Some headers are missing
:::

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**license\_not\_found** (400): License with the provided license user not found
:::

:::BlockQuote
**license\_not\_enabled** (400): The license is not enabled
:::

:::BlockQuote
**license\_not\_active** (400): The license is not active
:::

:::BlockQuote
**device\_not\_found** (400): An active device matching the hardware\_id not found
:::

:::BlockQuote
**blacklisted** (400): This device is blacklisted
:::

:::BlockQuote
**invalid\_license\_feature\_code** (400): License feature code: ' + param + ' is invalid or not assigned    to the license.
:::

:::BlockQuote
**floating\_not\_available** (400): No available slots for floating license.
:::


[title] OAuth Authorization
[path] License API/License API Authorization/

## Overview

The OAuth system allows for vendors to set up separate credentials for their Company, Customer Accounts, Customers or individual Licenses. Each entity has a **Client ID** and **Client Secret** (which can be set to rotate automatically). These are used to obtain an **Access Token&#x20;**&#x66;rom the OAuth endpoint, to be used for access to License API endpoints (as an alternative to [**API Key Authorization**](docId\:LNlwU0YzLtC1FNoS9VOQj)). Vendors can enforce a company-wide mandatory OAuth rule instead of API keys.

## Obtaining an Access Token

Access Tokens are short-lived secret strings used to authorize a client request on the API. To obtain an access token from the OAuth system, perform the following request:

:::ApiMethodV2
```json
{
  "name": "Request OAuth Token",
  "method": "POST",
  "url": "https://auth.licensespring.com/realms/user-portal/protocol/openid-connect/token",
  "description": "Generates an access token and returns an object containing the token and associated metadata",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "I37AUDwp1VWNVaxEzZi7V",
        "language": "curl",
        "code": "curl --location 'https://auth.licensespring.com/realms/user-portal/protocol/openid-connect/token' \\\n--header 'Content-Type: application/x-www-form-urlencoded' \\\n--data-urlencode 'client_id=CLIENT_ID_HERE' \\\n--data-urlencode 'client_secret=CLIENT_SECRET_HERE' \\\n--data-urlencode 'grant_type=client_credentials'",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "I37AUDwp1VWNVaxEzZi7V"
  },
  "results": {
    "languages": [
      {
        "id": "lcy-oCKwaqJHMVjVJ4cU5",
        "language": "200",
        "customLabel": "",
        "code": "{\n    \"access_token\": \"TOKEN_STRING_HERE\",\n    \"expires_in\": 480,\n    \"refresh_expires_in\": 0,\n    \"token_type\": \"Bearer\",\n    \"not-before-policy\": 0,\n    \"scope\": \"profile email\"\n}"
      },
      {
        "id": "_duVGZYrAgN08cJ0pX4ri",
        "language": "401",
        "code": "{\n    \"error\": \"invalid_client\",\n    \"error_description\": \"Invalid client or Invalid client credentials\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "lcy-oCKwaqJHMVjVJ4cU5"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "name": "Content-Type",
        "kind": "required",
        "type": "string",
        "description": "Must be: application/x-www-form-urlencoded",
        "": "Must be: application/x-www-form-urlencoded"
      }
    ],
    "bodyDataParameters": [],
    "formDataParameters": [
      {
        "name": "grant_type",
        "kind": "required",
        "type": "string",
        "description": "Must be: client_credentials",
        "": "Must be: client_credentials"
      },
      {
        "name": "client_id",
        "kind": "required",
        "type": "string",
        "description": "Client ID",
        "": "Client ID"
      },
      {
        "name": "client_secret",
        "kind": "required",
        "type": "string",
        "description": "Client Secret",
        "": "Client Secret"
      }
    ]
  },
  "currentNewParameter": {
    "label": "Form Parameter",
    "value": "formDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "request-oauth-token",
  "legacyHash": "dGnKRJcPb1mA1i_hsFsQ-"
}
```
:::

Once the access token is retrieved, it is used as an `Authentication: Bearer` value in License API requests. The `expires_in` property in the response states the Access Token's TTL in seconds from the moment the token was generated.

### Required Headers

Each client request must include the following headers:

::::WorkflowBlock
:::WorkflowBlockItem
**Date**

Current time given as a date string in [**RFC7231**](https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.1.1) format. Note that this value is always in the GMT timezone.

Example: `Date: Tue, 07 Jun 2014 20:51:35 GMT`
:::

:::WorkflowBlockItem
**Authorization**

This header contains the Access Token.

Examples: `Authorization: Bearer TOKEN_STRING_HERE`


:::
::::

:::hint{type="warning"}
Ensure that the Date header value is set to current time. The server allows timestamps that are up to 15 minutes old.
:::

## Client Access Permissions

Client ID-Secret pairs can be scoped for the following resources:

- **Company**: Provides access to all licenses belonging to the company
- **Customer Account**: Provides access to all licenses associated to a Customer Account
- **Customer**: Provides access to all licenses associated to an individual Customer
- **License**: Provides access to one specific license

Each Client ID string states the type of scope used, e.g.: `auth-company-100123`, `auth-customeraccount-200234`, `auth-customer-300345`, `auth-license-1000456`

## Errors in Endpoints

When calling a License API endpoint using the Access Token authorization, the system will return an error response if the Access Token is not valid. All returned errors have an HTTP status code of 400 or higher, and a response body as follows:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

The following errors related to Access Tokens can be returned:

:::BlockQuote
**oauth\_token\_malformed** (400)
:::

:::BlockQuote
**oauth\_token\_expired** (400)
:::

In case OAuth is enforced company-wide and a request is being sent using an API key:

:::BlockQuote
**oauth\_required** (400)
:::


[title] Response Signature
[path] License API/License API Authorization/

## Overview

Response objects from License API endpoints for activating and checking licenses contain a `license_signature` value, which is an HMAC-SHA256 signature used to verify the authenticity of the response. This mechanism ensures protection against counterfeit licensing servers and man-in-the-middle attacks.

## License Signature Details

When a webhook response is received, it includes a **license\_signature**. This signature is a secure hash generated using a server-side private key and is based on a specific format of the signing string.

### Signing String Format

The string to be signed is constructed as follows:

:::BlockQuote
LOWERCASE(HARDWARE\_ID#USER\_EMAIL\_OR\_LICENSE\_KEY#VALIDITY\_PERIOD)
:::

### Example Activation Request and Response

:::BlockQuote
\{
&#x20;  "hardware\_id": "A53F-0CBC-15FC-7E81-BF35-A720-A575-7C0C-8815-0463-DB78-E674-D140-CF15-85BB-EC01",
&#x20;  "license\_key": "FUH3-4E7A-LZJL-7JTP",
&#x20;  "product": "TP"
}
:::

:::BlockQuote
\{
&#x20;  "license\_signature": "60c22a575a67f5b2a1e9ff3fe204363046f1e5d097b8ebb468d903d0aaf739ac...",
&#x20;  "validity\_period": "2019-06-15T00:00:00.000Z",
&#x20;  "license\_type": "subscription",
&#x20;  ...
}
:::

### Constructed Signing String

Based on the above request and response:

:::BlockQuote
a53f-0cbc-15fc-7e81-bf35-a720-a575-7c0c-8815-0463-db78-e674-d140-cf15-85bb-ec01#fuh3-4e7a-lzjl-7jtp#2019-06-15t00:00:00.000z
:::

## Verifying the License Signature

You can use the server's public key to verify the **license\_signature**. By validating the signature, you ensure the response originates from LicenseSpring's trusted servers.

Download the server public key from the link below to implement signature verification using the example provided:

::File[]{src="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8_-OM1Oqw9QE45OBPr7Mt_prod.pub" signedSrc="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8_-OM1Oqw9QE45OBPr7Mt_prod.pub?AWSAccessKeyId=AKIAYQNQCIXNIQWBC56C&Expires=1691668099&Signature=kmfNsu%2BwWFWhPnWVh5gC3BpA2L4%3D" label="prod.pub"}

## Code Sample

```javascript
import crypto from 'node:crypto'
import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc.js'

dayjs.extend(utc)

const response = {
  // ... truncated license response ...
  "license_key": "163U-AKLB-5BNJ-VYOF-4567",
  "hardware_id": "6993f191bca2346c4015be4ff158805da70f10cd7d82aedd11dd38c2b47025a2",
  "validity_period": null,
  "license_signature": "VAkfjWGvQDl00YkjYS/1oCz........3HtzwFt8tQ=",
};

const signingString = `${
  licenseResponse.hardware_id
}#${
  licenseResponse.username
    ? licenseResponse.username.split('|')[0]
    : licenseResponse.license_key
}#${
  licenseResponse.validity_period ? dayjs(licenseResponse.validity_period).toISOString() : ''
}`.toLowerCase();

const verifier = crypto.createVerify('RSA-SHA256');
verifier.update(signingString);
const result = verifier.verify(publicKey, licenseResponse.license_signature, 'base64');

console.log(result); // if signature is valid, this will be "true"

```


[title] License API
[path] /

These endpoints are a set of RESTful APIs exposed for client applications and client SDKs. Can be used to activate/deactivate licenses, check licenses, handle metered usage. etc.

APIs are accessed through SSL and signed with API key + shared key combination.

Base URL: **api.licensespring.com**

See the following pages for further steps:

- [**Authorization**](docId\:KXIP7srfONTD_DEsDMSY3)&#x20;
- [**Floating**](docId:_b1eKLuwh8MyRBLNz4W8t)&#x20;
- [**Activate License (Online Method)**](docId\:Mt2yGm6CJzh2bumU-Gfww)&#x20;

:::hint{type="info"}
To edit license entitlements as well as orders, please refer to the [**Management API**](docId\:abk8afS7gBMtujL_Rd_4p)
:::

:::hint{type="warning"}
Encode emails which contain special symbols like '+' when sending them as parameters&#x20;

Example:*&#x20;test+symbol\@example.com* -> test%2Bsymbol%40example.com&#x20;
:::

:::hint{type="warning"}
When using param or body field product make sure that you are using product code, and not product name
:::


[title] Offline Request Schema
[path] License Entitlements/License Activation Types/

## Overview

As part of our ongoing efforts to strengthen security, we have introduced **Schema Version 2 (v2)** for offline requests. This update enhances request integrity by ensuring the entire payload is signed and verifiable.

## Schema Version 2 (v2) – Changes

Schema v2 introduces full payload signing and request versioning.

### Key Changes

1. **Schema Version Field**
   - Every request now includes a schema\_version field:
   - Allows License API to detect and handle the request format.
2. **HMAC-SHA256 Signature**
   - The entire request JSON is signed using HMAC-SHA256 with the client secret or shared key.
   - Ensures all fields are protected from tampering.
3. **Nested Request Object**
   - The signed request is wrapped in an outer JSON object:
   - The request field must remain a proper JSON object (not a string) to allow correct parsing and signature verification on the License API side.

### Example (v2)

:::BlockQuote
\{
&#x20; "request": \{
&#x20;   "schema\_version": 2,
&#x20;   "api\_key": "apikey",
&#x20;   "date": "Fri, 29 Aug 2025 07:22:37 GMT",
&#x20;   "hardware\_id": "8b06c6053b7a2040f07c60b62f17f378ccc5030e21676f8a100a97ab36303ad0",
&#x20;   "ip\_local": "192.168.1.226",
&#x20;   "license\_key": "BSK8-CLCY-PB5E-BXFO",
&#x20;   "mac\_address": "5A-8A-90-08-13-84",
&#x20;   "os\_hostname": "Mac",
&#x20;   "os\_ver": "Darwin 24.6.0",
&#x20;   "product": "fooapp",
&#x20;   "request": "activation",
&#x20;   "request\_id": "D010714E-72DD-E4CF-BEBB-4105EC1B2A0F",
&#x20;   "sdk\_lang": "cpp",
&#x20;   "sdk\_ver": "7.41.1",
&#x20;   "signature": "A7Tg3dBCc3OsegkPdPc6I1/sRqHj1uSuBR3ad8uaEnk="
&#x20; },
&#x20; "signature": "aad1693bf8b394719b695e916e07aee29d4ddf2afb24cc43febd4d43a660b703"
}
:::

## **Benefits of v2:**

- Full payload integrity: all fields are signed, including previously optional fields.
- Backward-compatible: older SDKs using v1 requests will still work while v2 enables enhanced security.
- Simplifies License API parsing and signature verification.

## Enabling Schema Version 2

To enable v2 for your offline requests:

1. Log in to the **Vendor Platform**.
2. In the left sidebar, go to **Settings** → **Preferences**.
3. Locate the **Minimum Offline Request Schema Version** section.
4. Select **V2** from the dropdown list.

By default, this setting is **Version 1**, so you must switch it to **Version 2** to start generating v2 offline requests.

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/2rSmwgHVPOH6zpWNbeoPF_image.png "Schema Version Selection")

:::hint{type="info"}
Offline schema v2 requires an SDK version that supports v2. Please check the [**SDK release notes&#x20;**](https://docs.licensespring.com/sdk)to ensure compatibility before enabling.&#x20;
:::

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/_sr1cvvtVoNEKqE7jLSIN_image.png)


[title] Licenses
[path] Vendor Platform/

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/vAy4dQSuIRusIMLBYgEdY_image.png "Licenses List View")

This view allows you to look up all licenses that have been issued in your account. Clicking on any of the licenses will allow you to view the details for that given license.

The main actions that you can achieve on the license summary view include:

- Searching for and looking up a license
- Import licenses via CSV
- Download licenses via CSV
- Create new licenses (orders).

You can click on "tab columns" to add or remove columns to the table:

![List of Optional Table Columns](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/4HoYGnsIUFOp9s0DlkbkK_image.png "List of Optional Table Columns")

The columns you can add/Remove for the License Summary View are:

- `Created on` Date on which a license was created
- `License Key/User` The actual key or first email address assigned to a user-based license
- `Product` The product for which the license was issued on
- `License Type` Allows you to see what [**License Type Options**](docId\:MIZEhBRPU9p6ydmFMG-jz) was issued
- `Expiration Date`  Time-limited and subscription-based licenses may have a value on when they are set to expire (or renew), if that field has been set for that license
- `Is trial` Will have an "x" symbol if the license is not of type trial, and a "checkmark" if the license is a trial license
- `Status` The status of the license (active/inactive/disabled)
- `Times activated` The number of devices that are currently node-locked to the license
- `Max activations` The maximum number of devices that the license allows to bind itself to
- `Prevent Virtual Machine` Boolean used to determine whether or not a license is allowed to run in a virtualized environment
- `Customer email`  The email address specified for the customer associated to the order for which the license belongs to
- `Customer name` The name field of the customer associated with the order for which the license belongs to
- `Customer company` The company of the customer associated with the order for which the license belongs to
- `Customer reference` The reference (if specified) of a customer associated with the order for which a  license belongs to
- `Customer labels`  Labels (if any) added to a customer.
- `Active` Boolean displaying if there is at least one active device on the license
- `Start Date` Timestamp added to a license in case a start date was specified for the license
- `Is bundle` Boolean that shows whether the license is for a product bundle (True) or for a single product (False)
- `Is air-gapped` A green checkmark appears if this license is meant to activate an air-gapped license policy
- `Is floating`  A green checkmark in this column if the license is meant to activate an on-prem floating license server.
- `Is floating cloud` Green checkmark in this column if the license is a cloud floating license.
- `Max simultaneous license users` Field used by both floating license types to determine max concurrent usage of the license. The Value will be N/A if the license is not of type floating
- `Can borrow` Green checkmark if the license is a floating license, and the default heartbeat can be overridden by a larger value
- `Max borrow time` Maximum time (in hours) that a floating license can be borrowed. N/A if the license is not a floating license or is a floating license and cannot be borrowed&#x20;
- `Max license users` Maximum number of users that can be assigned to a license
- `Enable maintenance period` Boolean determining whether there is a maintenance window defined for the license
- `Maintenance duration` Duration of the maintenance period starting from the first activation of the license
- `Maintenance End Date` End date when the license maintenance window expires
- `Max consumptions` If the license is of type consumption, this is the maximum consumptions allowed for that license
- `Total consumptions` Total consumptions counted on the license to date. N/A if this is not a license of type consumption
- `Product features`  Lists all feature codes that have are added to this license
- `Disabled on` If the license is disabled, this column will show the Date on which the license has been disabled on.
- `Activated on` This is the date that the license was last activated on. It is updated for every license activation
- `Last updated` Time stamp with the last modification to the licenses entitlements
- `Last checked` Time stamp with the last online license check
- `Valid duration` If the license is time-limited, the license's expiry date is counted on the time stamp of the first activation and this duration
- `Order` Order ID
- `Active Devices Up to Dates` Number of active devices using the latest product version
- `Note` Any note that is added to the license will appear in this column


[title] Billing
[path] Vendor Platform/Settings/

The billing section allows a platform user to perform billing-related tasks such as:

- Add payment information if paying by credit card
- Specify billing details that should appear on the invoice
- Retrieve invoices
- Add tax information

:::hint{type="info"}
LicenseSpring accepts payment by credit card for Monthly and for Annual term payments, and accepts Wire Transfers for Annual payments. To pay by Wire transfer, please contact us.
:::

:::hint{type="info"}
You can set permissions of platform users to restrict who can view and who can manage the billing section of your LicenseSpring account.
:::

## Pay Your Bill by Credit Card

Click on Settings > Billing and click on "Add Payment Method"

:::hint{type="info"}
if you do not see the "Add payment method" button, your account might have been configured for manual payment collection. If wish to pay automatically by credit card, place contact LicenseSpring's customer support
:::

![Adding Payment Method for Billing](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/H3t16cAj1FZ0WIEs3FM2a_image.png "Adding Payment Method for Billing")

Enter your credit card information on the screen displayed:

![Enter Payment Method Details](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/6oaq0Ag9dVCX6XtOmQxk6_image.png "Enter Payment Method Details")

## Change Billing Details

You can add your billing address and a point of contact by clicking on "Change Billing Details"

- This information will appear on the invoices created.
- The invoice will be sent to the email address specified

![Changing Billing Details](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/5_vXox4hntrQ4xJLRoqfO_image.png "Changing Billing Details")

## Add/Edit the Tax Identification Number

Scroll to the bottom of the billing detail view. It will allow you to specify the type of Tax ID you would like to add, and then specify the identification number itself:

![Changing Tax Details](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/4FkCFias-6G7Qn8lniCgq_image.png "Changing Tax Details")

![Selecting Tax Types and Number](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ed8RseLkFFi3p4bsP7_iX_image.png "Selecting Tax Types and Number")

The Tax ID will be added to the invoices we issue.

## Receive Invoice by Email

The email address you specify under billing will receive the invoices. You can also setup an email notification and specify additional email addresses to receive the invoice when its been finalized. Email notifications are setup under Settings > Notifications.


[title] The License Manager
[path] Portals/End-User Portal/

:::hint{type="info"}
A license manager is a user that is assigned to an order who can then log in to the user portal. Depending on their permissions, they can perform various edits to the licenses within the order.
:::

## Create a New License Manager in the Vendor Platform

You can define a new license manager in the vendor platform by clicking on the "orders" tab, and then on license managers. You can then click on "Add License Manager"



![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/2aEYaPuWSEf7vsb5uVl_6_image.png "Adding a License Manager")

Next, enter the email address of the license manager, as this is the only required field.

![Popup for Adding License Managers](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/XyEtRU8itCxfCjYsB56WH_image.png "Popup for Adding License Managers")

Clicking confirm will add the license manager to the LicenseSpring vendor platform.



![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/tdw7BimgPJs51pa0wKTB2_image.png "License Manager Detail View")

## Setting/Modifying Permissions for a License Manager

You can set the following permissions for a given license manager:

- `Reset license` Removes all devices activated on a given license.
- `Reset device` Deactivates a specific device that has been node locked to a machine.
- `Manage managers` Allows this license managers to add other license managers to a given order.
- `Manage license user credentials` Allows a license manager to view and reset the passwords of users assigned to a given license.
- `Manage license users` Allows the license manager to assign/unassign users to the user-based licenses for the orders they have been assigned to.
- `Issue license` Allows the license manager to issue licenses within orders they have been assigned to. The permission will set which products and license policies they are allowed to issue licenses with.
- `Create order` Allows license managers to create new orders that they will be assigned to.
- `Create bundle order` Allows the license manager to create new bundle orders that they will be assigned to.
- `Borrow License` Allows the license manager to borrow a license device on a floating license.

Under the `Permissions` tab on the license manager detail view, you can turn on and off these permissions.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/E_OCe8tN90t8iVnuQC5D3_image.png)

## Set Default Permissions When a New License Manager Is Created

When creating a new license manager, a default set of permissions will be assigned. You can set the default permissions from the license manager summary page:

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/7Bq-hPN2DjdgHDb6jD82g_image.png "License Manager Default Permissions")

## Add a License Manager to an Existing Order

You can add a license manager at any time after an order has been created and licenses have been issued. To do so, navigate to the order details screen, click on the `License managers` tab, and `Add license manager`:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/tszxZOKyXq7KIunhQPKla_image.png)

## License Manager Password Reset

A license manager can reset their password by going to the [**End-User Portal**](docId\:BOD5TlwkFFKiKasV1ZsrY), and entering their company code and email address. They will receive instructions on resetting their password by email.

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/E4wTjSEsJdSHI632cYLsP_image.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/E4wTjSEsJdSHI632cYLsP_image.png" size="54" width="506" height="554" position="center" caption="Reset Password Button" alt="Reset Password Button"}

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/xhPOMsX5RpHrLzKsoe6-E_image.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/xhPOMsX5RpHrLzKsoe6-E_image.png" size="54" width="661" height="595" position="center" caption="Password Reset Prompt" alt="Password Reset Prompt"}

:::hint{type="info"}
The license manager needs to enter the company ID along with their email address, since they might be assigned as license managers within multiple LicenseSpring accounts. The software vendor can find their Company ID under "Settings" > "Company Code".
:::

## License Manager Email Notifications

You can automatically send an email notification to a license manager when they are assigned to a new order and when other events occur.&#x20;

For more information, please review [**Email Notifications**](docId\:gKXhf0Gct6fNZVgLENN76).






[title] Customer Detail View
[path] Vendor Platform/Customers/

The customer detail view is where you would look up information on a specific customer, see any orders they have, and any licenses they are assigned to, along with logs.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/nC4Gdfh5pmd6V73tbpxws_image.png "Cutomer Detail VIew")

## Actions You Can Take on a Customer

- Edit customer details
- Add/remove customer labels
- Change customer accounts
- Delete the customer

## Edit Customer Details

A customer has the following fields that can be modified or left blank. The email address however, is a required field:

- `Email` **Required&#x20;**
- `First Name`
- `Last Name`
- `Address`
- `City`
- `State/Province`
- `Country`
- `Zipcode/Postcode`
- `Phone Number`
- `Company Name`
- `Reference` Customer reference number

## Add Customer Label

Customers can be filtered by their labels, which can be useful when searching for certain types of customers.

Click "Add label" and select an existing unapplied label to your customer, or create a new one and apply it to them.



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/GxdLMHGn4POOEo4jCmcSf_image.png "Customer Label Selection")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/U9l3dZ4HQRXTkaiVNt4-b_image.png)


[title] Air-Gapped License Policy
[path] Product Configuration/License Policies/

Air-gapped licenses allow ISVs to node-lock licenses on computers in air-gapped environments, where files are not allowed to leave the network once the software application has been deployed.&#x20;

Instead, the software is deployed alongside license policy files, which can then be selected, and node-locked through a series of code exchanges (instead of http requests or file exchanges).

## Creating Air-Gap License Policies:

On the product page ( saas.licensespring.com/\{companyID}/products/\{productID} ) go to `license policies` tab and click on a `add license policy` button.

To mark policy as air-gapped switch the `set as air-gapped` switcher under the title to true.

![Setting Policy as Air-Gapped](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/eMR0wc-zOCOgc_YB6bWzr_image.png "Setting Policy as Air-Gapped")

## Creating Air-Gapped License Files

You can either download the license file from the product license policy, or, if a license was set as "air-gapped", you can download the license policy file from the license detail page.

![Locating Air-Gap License Policy](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/6XY8KGGhpL7Y5ObNq8fPv_image.png "Locating Air-Gap License Policy")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/gzy8xQpJPRKCx9G3AGyI4_image.png)

## Activating an Air-Gapped License

The air-gap portal for license activation is available on this public URL: [**airgap.licensespring.com**](https://airgap.licensespring.com/)

Process of activation is done in 4 steps including actions on server (portal) and SDK:

### Step 1: Generate an Initialization Code

To start the license activation process, the user needs to enter the license key on the portal to initialize the air-gap license activation. This will create a one-time `initialization code`.

![Initialize Air-Gap Activation](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Xu1wViLbHxDn8NEH9L6aZ_image.png "Initialize Air-Gap Activation")

![Initialization Code](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/wE6hXZCAOa-LtMUQzydjM_image.png "Initialization Code")

The `initialization code` needs to be imported to the SDK alongside with the license key. The SDK will verify the initialization code and return the `activation code` and `hardware_id`.

:::hint{type="info"}
The initialization will generate a QR code containing the JSON with a `license_key` and an `initialization_code` included. This can help and remove the need for copy pasting or manually entering the codes.
:::

### Step 2: Generate Confirmation Code

When attempting to activate an air-gapped license, the SDK should be configured to activate activate an Air-gapped license. It will accept the `license_key`  as well as the `initialization_code`  and return the `hardware_id`  as well as an `activation code`  along with the license key. Go back to the air-gapped portal and click on "Enter air-gap activation code" and enter them in order to receive a confirmation code.

![Entering Air-Gap Activation Code](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/NulxpSsEXW7sosqurNgpq_image.png "Entering Air-Gap Activation Code")

![Entering Air-Gap Activation Code Pop-up](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/3urpjyiwDidqp1jJKrTh5_image.png "Entering Air-Gap Activation Code Pop-up")

![License Has Been Activated Pop-up](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/y8RuJVgUTItw5tuN190rh_image.png "License Has Been Activated Pop-up")

The license key, hardware ID, policy ID and this new signature `confirmation code` need to be input into the SDK. The SDK validates the code using company account public air-gap key which is also previously embedded in to the SDK. If successful, the SDK will use the policy ID to retrieve the license entitlements and use this as a local license file.

Generated QR code contains the JSON with `license_key`, `hardware_id`, `policy_id` and `confirmation_code` included which you can scan and then send or save. This can help and remove the need for manually copy pasting the codes.

[title] Activations & Device Transfers
[path] License Entitlements/

Activations are the term we use to denote the process of binding a device to a license. There are a few fields that allow you to control the node-locking properties of your software license, these are `Max Activations` , `Times activated` , `transfer count,` and `allow offline activation:`

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/vb_JGJIvG-TdwgTT8COQt_image.png)

## Max Activations

`Max Activations` refers to the maximum number of distinct devices that can activated against a license.

## Allow Offline Activation

By default every license can be activated using online, offline or airgap activation process.

If you want to limit your licenses to be activated only online, you can toggle the Allow offline activation checkbox on a license.

When set to `False`, the License API will not allow the license to be activated offline or airgap ( airgap being a variation of offline licensing ).

## Times Activated

When issued, a license always starts with a times activated of 0. Each time a license is activated (bound to a device), the value for total activations increments by 1, when a device is deactivated from a license, the `Times activated` field will decrement by 1. Total activations must always be less than or equal to `Max Activations`&#x20;

## Transfer Count

When a license is deactivated on a device and then activated on a different device, the `Transfer count`  will increment by 1.

:::hint{type="info"}
You can set rules around transfering licenses across devices. For example, you can **prevent device transfers,** or only allow &#x61;**&#x20;license transfer a limited number of times.**
:::

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/_Qq0Wu4RKmyMUGe2Etz0E_image.png)

:::hint{type="info"}
**Prevent Device Transfers**
When this option is checked, the license becomes permanently bound to the first machine where it is activated. This is also known as a **Node-Locked license** in our terminology. It means the license cannot be moved or re-activated on any other device, even if it is later deactivated. In other words, checking this box enforces a permanent binding of the license to a single machine.&#x20;

**Has Device Transfer Limit**
When this option is enabled, you can define the maximum number of times a license may be transferred between machines. A transfer occurs when the license is deactivated on one device and then reactivated on another. For example, if the limit is set to **3**, the license can be moved up to three times in total. If this option is left unchecked, transfers are unlimited (as long as the license is properly deactivated before reactivation).

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/kzoKtu7d8-okHKiwzyiAE_image.png "Device Transfer Limit")
:::




[title] Deactivate License (Offline Method)
[path] License API/License Activation/Deactivation/

:::hint{type="info"}
Currently we support trial, perpetual and consumption license types for offline deactivation purposes
:::

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/deactivate_offline",
  "name": "/api/v4/deactivate_offline",
  "method": "POST",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [
      {
        "name": "base64-encoded JSON object",
        "kind": "required",
        "type": "Object",
        "description": "The request body is a base64-encoded stringified JSON object containing the properties below. See the \"Finalized payload\" section for examples on how to generate this payload",
        "children": [
          {
            "name": "api_key OR client_id",
            "kind": "required",
            "type": "string",
            "description": "Company API key"
          },
          {
            "name": "date",
            "kind": "required",
            "type": "string",
            "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
          },
          {
            "name": "request_id",
            "kind": "required",
            "type": "string",
            "description": "Custom unique ID used to identify the request"
          },
          {
            "name": "request",
            "kind": "required",
            "type": "string",
            "description": "Determines the type of request: \"activation\" or \"deactivation\""
          },
          {
            "name": "signature",
            "kind": "required",
            "type": "string",
            "description": "Calculated request signature (see section below)"
          },
          {
            "name": "product",
            "kind": "required",
            "type": "string",
            "description": "Product short code"
          },
          {
            "name": "hardware_id",
            "kind": "required",
            "type": "string",
            "description": "Unique hardware ID generated for the client device"
          },
          {
            "name": "license_key",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is key-based (see section below)"
          },
          {
            "name": "username",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is user based (see section below)"
          },
          {
            "name": "license_id",
            "kind": "optional",
            "type": "string",
            "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user"
          },
          {
            "name": "sdk_ver",
            "kind": "optional",
            "type": "string",
            "description": "SDK version string which will be logged"
          },
          {
            "name": "consumptions",
            "kind": "optional",
            "type": "number",
            "description": "Increases/decreases total_consumptions"
          },
          {
            "name": "product_features",
            "kind": "optional",
            "type": "array",
            "description": "An array of `{ \"feature\": string, \"consumptions\": number }` objects which will add consumptions to those license features. The consumption number may be negative if negative consumptions are allowed on the license"
          }
        ],
        "schema": [
          {
            "name": "api_key OR client_id",
            "kind": "required",
            "type": "string",
            "description": "Company API key"
          },
          {
            "name": "date",
            "kind": "required",
            "type": "string",
            "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
          },
          {
            "name": "request_id",
            "kind": "required",
            "type": "string",
            "description": "Custom unique ID used to identify the request"
          },
          {
            "name": "request",
            "kind": "required",
            "type": "string",
            "description": "Determines the type of request: \"activation\" or \"deactivation\""
          },
          {
            "name": "signature",
            "kind": "required",
            "type": "string",
            "description": "Calculated request signature (see section below)"
          },
          {
            "name": "product",
            "kind": "required",
            "type": "string",
            "description": "Product short code"
          },
          {
            "name": "hardware_id",
            "kind": "required",
            "type": "string",
            "description": "Unique hardware ID generated for the client device"
          },
          {
            "name": "license_key",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is key-based (see section below)"
          },
          {
            "name": "username",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is user based (see section below)"
          },
          {
            "name": "license_id",
            "kind": "optional",
            "type": "string",
            "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user"
          },
          {
            "name": "sdk_ver",
            "kind": "optional",
            "type": "string",
            "description": "SDK version string which will be logged"
          },
          {
            "name": "consumptions",
            "kind": "optional",
            "type": "number",
            "description": "Increases/decreases total_consumptions"
          },
          {
            "name": "product_features",
            "kind": "optional",
            "type": "array",
            "description": "An array of `{ \"feature\": string, \"consumptions\": number }` objects which will add consumptions to those license features. The consumption number may be negative if negative consumptions are allowed on the license"
          }
        ]
      }
    ],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "es8g1cuKJMbNPiIVt9VoF",
        "code": "{\n  \"request\": \"deactivation\",\n  \"license_key\": \"GAWDA-BMRZ-YWEL-3KTP\",\n  \"username\": \"test@example.com\", // if user based licenses\n  \"request_id\": \"4D75-4BB1-98B3-FD58B705B52E\",\n  \"license_signature\": \"2/7gGLn1HHvmrVCHXo=\",\n  \"validity_period\": null,\n  \"maintenance_period\": \"2029-10-24T00:00:00.000Z\",\n  \"license_type\": \"perpetual\",\n  \"is_trial\": false,\n  \"product_features\": [{\n          \"name\": 'feature 3',\n          \"code\": 'F3',\n          \"feature_type\": 'activation',\n          \"allow_overages\": false,\n          \"max_overages\": 0,\n          \"expiry_date\": '2022-02-25'\n      },\n      {\n          \"name\": 'feature 4',\n          \"code\": 'F4',\n          \"feature_type\": 'consumption',\n          \"max_consumption\": 10,\n          \"total_consumptions\": 0,\n          \"expiry_date\": null\n      }\n  ],\n  \"max_activations\": 1,\n  \"times_activated\": 0,\n  \"custom_fields\": [\n    {\n      \"name\": \"custom field\",\n      \"data_type\": null,\n      \"value\": \"has a value\"\n    },\n    {\n      \"name\": \"TestFieldName\",\n      \"data_type\": null,\n      \"value\": \"TestFieldValue\"\n    }\n  ],\n  \"product details\": {\n    \"product_name\": \"Test\",\n    \"short_code\": \"TT\",\n    \"allow_trial\": true,\n    \"trial_days\": 15,\n    \"authorization_method\": \"license-key\",\n    \"allow_overages\": true,\n    \"max_overages\": 10\n  }\n}",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "7eyIlKSv2QgJcowEsDZ-2",
        "code": "",
        "language": "400",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "7eyIlKSv2QgJcowEsDZ-2"
  },
  "examples": {
    "languages": [
      {
        "id": "puj0dcIAUBP2lzA0C4v25",
        "language": "curl",
        "code": "curl --location --request POST '/api/v4/deactivate_offline' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string' \\\n--data-raw '_BASE64_PAYLOAD_HERE_'",
        "customLabel": ""
      },
      {
        "id": "_WTy9a00WCt4a6fYHHV1Y",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'POST',\n   'url': '/api/v4/deactivate_offline',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   },\n   body: Buffer.from(JSON.stringify(offline_payload)).toString('base64')\n};\n\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "AFNfEcpNDBtfvuFwE8c92",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: btoa(JSON.stringify(offline_payload)),\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/deactivate_offline\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "k0Fc_tZWU0Tbqadtqa0Hn",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/deactivate_offline\"\n\npayload = \"{\\\"Payload\\\":\\\"Object\\\"}\"\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "uO7w84epBz9ep8ZCe-6B1",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/deactivate_offline\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\nrequest.body = \"{\\\"Payload\\\":\\\"Object\\\"}\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "AFNfEcpNDBtfvuFwE8c92"
  },
  "description": "Deactivates a license for a specific computer identified by hardware ID using the ls_activation.req file\n",
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4deactivateoffline",
  "legacyHash": "dzna-uJjVyESkysVA0MKD"
}
```
:::

## Schema

### Request Body

The request body is a string representing a base64-encoded JSON object containing all the required activation data.

:::hint{type="danger"}
If using "multipart/form-data" for the request, the "file" form parameter is mandatory
:::

:::CodeblockTabs
```typescript
type LicenseOfflineActivationObject = ({

  // for key-based licenses:
  license_key: string

} | {

  // for user-based licenses:
  username: string
  password: string

}) & {

  // required properties:
  hardware_id: string
  product: string
  request_id: string
  signature: string
  date: string
  request: "activation"
  
} & ({
  api_key: string // for API key authorization
} | {
  client_id: string // for OAuth authorization
}) & {

  // optional properties:
  bundle_code?: string | undefined
  license_id?: number | undefined
  is_vm?: boolean | undefined
  vm_info?: string | undefined
  os_ver?: string | undefined
  hostname?: string | undefined
  os_hostname?: string | undefined
  ip?: string | undefined
  ip_local?: string | undefined
  app_ver?: string | undefined
  sdk_ver?: string | undefined
  mac_address?: string | undefined
  consumptions?: number | undefined
  product_features?: {
    feature: string,
    consumptions: number,
  }[]
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "allOf": [
    {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "license_key": { "type": "string" }
          },
          "required": ["license_key"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "username": { "type": "string" },
            "password": { "type": "string" }
          },
          "required": ["username", "password"],
          "additionalProperties": false
        }
      ]
    },
    {
      "type": "object",
      "properties": {
        "api_key": { "type": "string" },
        "client_id": { "type": "string" },
        "request": { "type": "string" },
        "request_id": { "type": "string" },
        "date": { "type": "string" },
        "signature": { "type": "string" },
        "hardware_id": { "type": "string" },
        "product": { "type": "string" },
        "bundle_code": { "type": "string" },
        "license_id": { "type": "number" },
        "is_vm": { "type": "boolean" },
        "vm_info": { "type": "string" },
        "os_ver": { "type": "string" },
        "hostname": { "type": "string" },
        "os_hostname": { "type": "string" },
        "ip": { "type": "string" },
        "ip_local": { "type": "string" },
        "app_ver": { "type": "string" },
        "sdk_ver": { "type": "string" },
        "mac_address": { "type": "string" },
        "consumptions": { "type": "number" }, 
        "product_features": {
          "type": "object",
          "properties": {
            "feature": { "type": "string" },
            "consumptions": { "type": "number" }
          }
        }
      },
     "allOf": [
        { "anyOf": [{ "required": ["api_key"] }, { "required": ["client_id"] }] },
        { "anyOf": [{ "required": ["license_key"] }, { "required": ["username"] }] }
      ],
      "required": ["hardware_id", "product", "date", "signature"],
      "additionalProperties": false
    }
  ]
}
```
:::

### Signature

The `signature` value is constructed as follows:

1. The string `licenseSpring` plus a newline
2. The string `date`, plus the "date" value from the license payload object, plus a newline
3. Either the "license\_key" or "username" value from the request payload object (which ever is present on the license, see the License Authorization Method section below) plus a newline
4. The "hardware\_id" value from the request payload object plus a newline
5. The "api\_key" value from the request payload object

This complete string is then encrypted using **HMAC-SHA256** and the company **shared key** as the encryption key.

```javascript
import crypto from 'node:crypto';

const activationPayload = {
  // ...payload content...
};

// api_key or client_id depending on authorization type used:
const key = (activationPayload.api_key || activationPayload.client_id);

// if using API key authorization: the signing key is the Shared Key
// if using OAuth: the signing key is the Client Secret
const signingKey = '...';

const signingString =
  'licenseSpring\n' +
  'date: ' + activationPayload.date + '\n' +
  (activationPayload.license_key || activationPayload.username) + '\n' +
  activationPayload.hardware_id + '\n' +
  key;

  const signature = crypto
    .createHmac('sha256', signingKey)
    .update(signingString)
    .digest('base64');
```

### Finalized payload

This object is then stringified and encoded to base64, e.g.:

:::CodeblockTabs
JS Browser

```javascript
const activationPayload = {
  // ...payload content...
};
const requestBody = btoa(JSON.stringify(activationPayload));
```

nodeJS

```javascript
const activationPayload = {
  // ...payload content with "signature" property...
};
const requestBody = Buffer.from(JSON.stringify(activationPayload)).toString('base64');
```
:::

### Response Body

If the request succeeds, the endpoint responds with the HTTP code 200 and the string `license_deactivated`.

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

### Key-based product licenses

Each license assigned to the product requires the client to provide a license key in order to activate, check or deactivate the license (property `license_key` in the request body).

The license response object will contain the `license_key` property, and the property `product_details.authorization_method` will be the string `license_key`.

### User-based product licenses

Each license assigned to the product has a corresponding "license user" instead of a license key. There are multiple ways a user-based product license can be accessed when making a request:

- By providing the values for `username` and `password` for the license user
- By providing the values for `id_token` and `customer_account_code` if using single sign-on authentication using Implicit grant
- By providing the values for `code` and `customer_account_code` if using single sign-on authentication using Authorization code grant
-

In the license response object, `product_details.authorization_method` will have the string value `user` and the response object will contain the `user` object with information on the license user.&#x20;

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**missing\_headers** (400): some headers are missing
:::

- when missing authorization or date headers

:::BlockQuote
**missing\_parameters** (400): some parameters are missing in the request: different, parameters
:::

- when no request body at all or no file found in request body

:::BlockQuote
**authorization\_missing\_params** (400): some parameters are missing in authorization: different, parameters
:::

- when has request body but request body is not properly base 64 encoded
- when file is missing in request body
- when license\_key or hardware\_id body parameters are missing
- when data body parameter is missing
- when api\_key parameter is missing

## Guide on using Offline Licenses

&#x20;If any aspect of the offline licensing model remains unclear or raises questions, we encourage you to explore our in-depth guide on[ ](https://app.archbee.com/docs/FbT_Z5Cu33D-LVZx1fRkU/FEyF5UIc8A7RvjQ9LCz3g)[**Offline License Activation**](docId\:FEyF5UIc8A7RvjQ9LCz3g)

This resource offers a comprehensive explanation of the offline licensing process, how it operates, and ways to utilize its advantages for your specific software applications

[title] Features
[path] License Entitlements/

:::hint{type="info"}
Please visit our article on [**Product Features**](docId:2ITHkUrk5-QDlw0cet-nz) for more information.
:::

Features allow you to turn on and off individual modules or components of your software product, as well as to meter their usage.

![Editing features on an existing license](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Qs0-33z9R0aXGdYG0f9kI_image.png "Editing features on an existing license")

## Examples of Features Licensing

- Giving access to additional functionality within your software
- metering API usage for different types of requests
- Setting the number of reports that can be pulled from a database

## Types of Features Available on LicenseSpring

We offer two type of license features:

- **Activation Features&#x20;**&#x61;re added or removed from a license, and can have an expiry date to them, but have no further functionality.
- **Consumption Features** can be added to or removed from a license and also can have an expiry date set. However, they are have a field to keep track of a few other values:
  - `Total consumptions`: times this feature was used
  - `Max consumptions`: the number of times the feature is allowed to be used
  - `Max overages`: the number of times the feature is allowed to be used beyond the value set for `Max Consumptions`&#x20;

## Adding/Removing Features to a License

You can select which features to add to a license at the moment of issuing them, or by editing an existing license. To change which features should be available for an existing license, navigate to the license details page, and click on "product features"

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Wl0GJGN1zIjHeEMlDe3GS_image.png)

### Adding a Feature to a License

:::hint{type="info"}
Make sure you first defined the product feature, otherwise you won't have anything to add to the license!
:::

Click "Add product feature", and then select from the "remaining product features" dropdown which features to add to the license. If the feature is a consumption feature, you can also set values for `Max consumption` , `Max overages` , and `Consumption period`  that is different from the default.

You can also add an expiry date when adding the feature to the license!



![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/u1Mn6yur_jaVBWreWY4Jc_image.png "Adding New Product Feature")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/9wDW8hgXzRPnqw6pJhxGt_image.png)

### Adding an Expiry Date to an Existing Feature

Click on the pencil on the right side of the row with the feature, and you will be able to set/remove an expiry date for that feature. The feature will be automatically removed from the license on the specified date at 00:00 UTC.

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/y0AAqytKeHpRXHt77bF0H_image.png "Edit ")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/EX-tWm_8vFcRxbS4MAKO6_image.png)

### Removing a Feature From a License

Click on the red trash icon on the right side of the screen to remove a feature from a license.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/SIWQRyH85TrzaXeAXSnQF_image.png)


[title] License Activation/Deactivation
[path] License API/

The following articles explain how to activate or deactivate Licenses.&#x20;

## License Activation Types

The API provides options for activating/deactivating licenses using either the Online method or Offline method. For a detailed explanation on Online vs. Offline see: [**License Activation Types**](https://docs.licensespring.com/activation-types)

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

### Key-based product licenses

Each license assigned to the product requires the client to provide a license key in order to activate, check or deactivate the license (property `license_key` in the request body).

The license response object will contain the `license_key` property, and the property `product_details.authorization_method` will be the string `license_key`.

### User-based product licenses

Each license assigned to the product has a corresponding "license user" instead of a license key. There are multiple ways a user-based product license can be accessed when making a request:

- By providing the values for `username` and `password` for the license user
- By providing the values for `id_token` and `customer_account_code` if using single sign-on authentication using Implicit grant
- By providing the values for `code` and `customer_account_code` if using single sign-on authentication using Authorization code grant

In the license response object, `product_details.authorization_method` will have the string value `user` and the response object will contain the `user` object with information on the license user.&#x20;

## License Types

The `license_type` property defines one of the 4 types of licenses based on their duration and how the license is used:

- Perpetual: `perpetual`
- Time-limited: `time-limited`
- Subscription: `subscription`
- Consumption: `consumption`

For more information see: [**License Types**](docId\:xHxttCVj7gs6qeAqu7Cua)&#x20;

## API Methods

- [**Activate License (Online Method)**](docId\:Mt2yGm6CJzh2bumU-Gfww)&#x20;
- [**Deactivate Bundle (Online Method)**](docId\:nzu6SRyNQLlEd2_-HhvhR)&#x20;
- [**Deactivate Bundle (Offline Method)**](docId\:UCxi3f0Ly0ysvOuQHH8lF)&#x20;
- [**Deactivate License (Offline Method)**](docId\:iyg1DXIYqp9vW-Mlj-xUk)&#x20;
- [**Activate Bundle (Online Method)**](docId\:sj4ujBbDqwMf3QJDVNHdh)&#x20;




[title] Deactivate Bundle (Online Method)
[path] License API/License Activation/Deactivation/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/deactivate_bundle",
  "name": "/api/v4/deactivate_bundle",
  "method": "POST",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "String",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "kind": "optional",
        "name": "license_key",
        "type": "string",
        "children": [],
        "description": "Required if product is key-based (see section below)"
      },
      {
        "kind": "optional",
        "name": "username",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "kind": "optional",
        "name": "id_token",
        "type": "string",
        "children": [],
        "description": "Required if using SSO (see section below). This is the id_token received from the SSO if Implicit grant authorization method is being used."
      },
      {
        "kind": "optional",
        "name": "code",
        "type": "string",
        "children": [],
        "description": "Required if using SSO (see section below). This is the code received from the SSO if Authorization code grant method is being used."
      },
      {
        "kind": "optional",
        "name": "customer_account_code",
        "type": "string",
        "children": [],
        "description": "Required if using SSO (see section below). This is the customer_account_code to which SSO provider is configured. "
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "Number",
        "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "children": []
      },
      {
        "name": "sdk_ver",
        "kind": "optional",
        "type": "string",
        "description": "Version of the SDK used",
        "": "Version of the SDK used"
      }
    ],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "es8g1cuKJMbNPiIVt9VoF",
        "code": "license_deactivated",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "7eyIlKSv2QgJcowEsDZ-2",
        "code": "{\n    \"unknown_product\": \"Provided product was not found\",\n    \"license_not_found\": \"License with the provided license user not found\",\n    \"license_not_enabled\": \"The license is not enabled\",\n    \"vm_not_allowed\": \"Virtual machine not allowed\",\n    \"offline_floating_cloud_not_supported\": \" Floating cloud licenses cannot be activated offline.\",\n    \"license_start_date_error\": \"This license cannot be activated before start date: {date}\",\n    \"blacklisted\": \"This device is blacklisted\",\n    \"license_activated_max_times\": \"This license  has already been activated the maximum number of times\",\n    \"license_user_activated_max_times\": \"License user has activated this license max times\",\n    \"license_expired\": \"License validity period has expired.\",\n    \"license_transferred_max_times\": \"This license has already been transferred the maximum number of times\",\n    \"license_device_exists\": \"A device matching this hardware_id is already created on the license\"\n}",
        "language": "400",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "es8g1cuKJMbNPiIVt9VoF"
  },
  "examples": {
    "languages": [
      {
        "id": "xgX5uw4vq7BJNbqvQ_ia0",
        "language": "curl",
        "code": "curl --location --request POST '/api/v4/deactivate_license' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string' \\\n--data-raw '{\"hardware_id\":\"String\",\"product\":\"string\",\"license_key\":\"string\",\"username\":\"string\",\"password\":\"string\",\"id_token\":\"string\",\"code\":\"string\",\"customer_account_code\":\"string\",\"is_vm\":\"Boolean\",\"vm_info\":\"string\",\"os_ver\":\"string\",\"hostname\":\"string\",\"os_hostname\":\"string\",\"ip\":\"string\",\"ip_local\":\"string\",\"app_ver\":\"string\",\"sdk_ver\":\"string\",\"mac_address\":\"string\"}'",
        "customLabel": ""
      },
      {
        "id": "3Fz0Q_qaZA0RnhG5k5R_W",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'POST',\n   'url': '/api/v4/deactivate_license',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   },\n   body: '{\"hardware_id\":\"String\",\"product\":\"string\",\"license_key\":\"string\",\"username\":\"string\",\"password\":\"string\",\"id_token\":\"string\",\"code\":\"string\",\"customer_account_code\":\"string\",\"is_vm\":\"Boolean\",\"vm_info\":\"string\",\"os_ver\":\"string\",\"hostname\":\"string\",\"os_hostname\":\"string\",\"ip\":\"string\",\"ip_local\":\"string\",\"app_ver\":\"string\",\"sdk_ver\":\"string\",\"mac_address\":\"string\"}'\n\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "uJvCS-wF1cAIBTUqKJTug",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar raw = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"password\\\":\\\"string\\\",\\\"id_token\\\":\\\"string\\\",\\\"code\\\":\\\"string\\\",\\\"customer_account_code\\\":\\\"string\\\",\\\"is_vm\\\":\\\"Boolean\\\",\\\"vm_info\\\":\\\"string\\\",\\\"os_ver\\\":\\\"string\\\",\\\"hostname\\\":\\\"string\\\",\\\"os_hostname\\\":\\\"string\\\",\\\"ip\\\":\\\"string\\\",\\\"ip_local\\\":\\\"string\\\",\\\"app_ver\\\":\\\"string\\\",\\\"sdk_ver\\\":\\\"string\\\",\\\"mac_address\\\":\\\"string\\\"}\";\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/deactivate_license\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "oHvG2_KC9rAafj9m1qUOF",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/deactivate_license\"\n\npayload = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"password\\\":\\\"string\\\",\\\"id_token\\\":\\\"string\\\",\\\"code\\\":\\\"string\\\",\\\"customer_account_code\\\":\\\"string\\\",\\\"is_vm\\\":\\\"Boolean\\\",\\\"vm_info\\\":\\\"string\\\",\\\"os_ver\\\":\\\"string\\\",\\\"hostname\\\":\\\"string\\\",\\\"os_hostname\\\":\\\"string\\\",\\\"ip\\\":\\\"string\\\",\\\"ip_local\\\":\\\"string\\\",\\\"app_ver\\\":\\\"string\\\",\\\"sdk_ver\\\":\\\"string\\\",\\\"mac_address\\\":\\\"string\\\"}\"\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "urxE_DgGNxfjEo27HuGSl",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/deactivate_license\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\nrequest.body = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"password\\\":\\\"string\\\",\\\"id_token\\\":\\\"string\\\",\\\"code\\\":\\\"string\\\",\\\"customer_account_code\\\":\\\"string\\\",\\\"is_vm\\\":\\\"Boolean\\\",\\\"vm_info\\\":\\\"string\\\",\\\"os_ver\\\":\\\"string\\\",\\\"hostname\\\":\\\"string\\\",\\\"os_hostname\\\":\\\"string\\\",\\\"ip\\\":\\\"string\\\",\\\"ip_local\\\":\\\"string\\\",\\\"app_ver\\\":\\\"string\\\",\\\"sdk_ver\\\":\\\"string\\\",\\\"mac_address\\\":\\\"string\\\"}\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "xgX5uw4vq7BJNbqvQ_ia0"
  },
  "description": "Dectivate a license for a product\n",
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4deactivatebundle",
  "legacyHash": "nfu_UCHm2-CiBeU98AfrR"
}
```
:::

## Schema

### Request Body

:::CodeblockTabs
```typescript
type LicenseActivationRequestBody = ({

  // for key-based licenses:
  license_key: string

} | {

  // for user-based licenses:
  username: string
  password: string

} | {

  // for user-based licenses using single sign-on Implicit grant:
  id_token: string
  customer_account_code: string

} | {

  // for user-based licenses using single sign-on Authorization code grant:
  code: string
  customer_account_code: string

}) & {

  // required properties:
  hardware_id: string
  product: string

  // optional properties:
  license_id?: number | undefined
  sdk_ver?: string | undefined
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "allOf": [
    {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "license_key": { "type": "string" }
          },
          "required": ["license_key"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "username": { "type": "string" },
            "password": { "type": "string" }
          },
          "required": ["username", "password"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "id_token": { "type": "string" },
            "customer_account_code": { "type": "string" }
          },
          "required": ["id_token", "code", "customer_account_code"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "code": { "type": "string" },
            "customer_account_code": { "type": "string" }
          },
          "required": ["id_token", "code", "customer_account_code"],
          "additionalProperties": false
        }
      ]
    },
    {
      "type": "object",
      "properties": {
        "hardware_id": { "type": "string" },
        "product": { "type": "string" },
        "license_id": { "type": "number" },
        "sdk_ver": { "type": "string" }
      },
      "required": ["hardware_id", "product"],
      "additionalProperties": false
    }
  ]
}
```
:::

### Response Body

If the request succeeds, the endpoint responds with the HTTP code 200 and the string `license_deactivated`.

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

### Key-based product licenses

Each license assigned to the product requires the client to provide a license key in order to activate, check or deactivate the license (property `license_key` in the request body).

The license response object will contain the `license_key` property, and the property `product_details.authorization_method` will be the string `license_key`.

### User-based product licenses

Each license assigned to the product has a corresponding "license user" instead of a license key. There are multiple ways a user-based product license can be accessed when making a request:

- By providing the values for `username` and `password` for the license user
- By providing the values for `id_token` and `customer_account_code` if using single sign-on authentication using Implicit grant
- By providing the values for `code` and `customer_account_code` if using single sign-on authentication using Authorization code grant



In the license response object, `product_details.authorization_method` will have the string value `user` and the response object will contain the `user` object with information on the license user.&#x20;

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of Exceptions

:::BlockQuote
**unknown\_product&#x20;**(400): Provided product was not found
:::

:::BlockQuote
**product\_not\_bundle** (400): Specified product "code" is not a bundle
:::

:::BlockQuote
**license\_not\_found** (400): License with the provided license user not found
:::

:::BlockQuote
**license\_not\_active&#x20;**(400): The license is not active
:::

:::BlockQuote
**device\_not\_found** (400): An active device matching the hardware\_id not found
:::

:::BlockQuote
**missing\_headers&#x20;**(400): Some headers are missing
:::

###


[title] User Groups
[path] Vendor Platform/Untitled/

User groups let you manage multiple users simultaneously, simplifying tasks such as assigning licenses, configuring permissions, and organizing teams. By grouping users, you can streamline administrative tasks and ensure consistent access across your organization.&#x20;

### Adding Users to a User Group

Steps:

1. Navigate to the **User Groups** section

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/tRv8sMHM8Q8l49IaEcjMe_image.png)

&#x20;   2\.  Select an **existing group** or create a new one by clicking **Add New User Group.**

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/L8IaSN6Xlbo0j9OWiF8dY_image.png)

&#x20;     3\.  After selecting a user group, you can **add users, assign licenses, and designate license managers.&#x20;**

### Why Create User Groups?

User groups are especially useful when managing licenses and permissions at scale. Instead of assigning and tracking licenses for each individual user, you can manage access for entire teams or departments in one place. This helps:

- **Save time**: apply changes once to a group instead of repeating them for each user.
- **Ensure consistency**: all members of the group automatically receive the same licenses and permissions.
- **Simplify onboarding:&#x20;**&#x6E;ew users only need to be added to the right group to receive everything they need.
- **Improve organization:** structure your users by role, department, or project for clearer oversight.
- **Enable delegated management**: assign license managers to groups so responsibility can be shared without losing control.


[title] Product Bundles
[path] Product Configuration/

A product bundle is a specific type of product which groups several products together so that they can be activated and used with a single license.

## General Process: Working With Product Bundles:

Generally, creating product bundles uses the following workflow:

- Step 1: Initialize a product bundle
- Step 2: Issue licenses for the product bundle.
- Step 3: Activate each product individually using the same license.

## Initialize a Product Bundle

Product bundles can be created on the Products page in the platform clicking on the button Add new bundle.

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/xFLRypQZlMRTJD_nfN1HB_image.png "Adding a New Bundle")

Enter the bundle name, code, authorization method select all the products which are going to be included in a bundle.

![Setting Bundle Values](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/NSZLjERf_0z-fFMdNcb24_image.png "Setting Bundle Values")

:::hint{type="info"}
The bundle code must be unique from other bundle and other product codes
:::

:::hint{type="info"}
You can only bundle products using the same authorization method
:::

:::hint{type="info"}
The Bundle code, authorization method and selected products cannot be edited after the bundle is created. You can edit their name, and delete or disable / re-enable them at a later date.
:::

## Issuing Bundle Licenses in the Vendor Platform:

:::hint{type="info"}
An order for bundles can only contain product licenses or bundle licenses, but not both.
:::

Start as you normally would with any other license:

1. Open the Order Creator, and optionally add Customer and order information. Press "Next"
2. Toggle "Create order for product bundle"

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ED9wfbpLrGC3DW1vpzmXx_image.png)

In the product bundle selector:

- Select the bundle you wish to issue licenses for.
- Specify the license policy to be associated for each product individually.
- Click "Confirm", "next" and "Create order"



![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/0zqEVZA0epwYtp-LbaAzx_image.png "Confirming Bundle Configuration")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ZtSPENpJGkPzuh8DW-ZE5_image.png)

The License Key can be found in the order:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/jtJuqJWvqzA2nC2hOWsPD_image.png)

## Activating Licenses for Bundled Products

The License created for the bundle can be used to activate the products within the bundle. The products needs to be activated separately. For example, you cannot use the bundle code to activate the license for all of the products in that bundle.

## Assigning Users to User-Based Product Bundles

Users are assigned to the user-based bundle license and can then log in to the individual products using the same credentials separately.

:::hint{type="warning"}
There is no way to assign users to individual products of a bundle. In other words, a user will be assigned to all products within the bundle. The `Max users` will therefore be the smallest value of the `Max users` of all the individual license policies used.
:::

## Activating Licenses of Bundles through the LicenseAPI

The API interfaces remain consistent, as we continue to operate with standard licenses for processes such as activation and verification.

For instance, consider a license bundle named "Bundle PRO" with the code "bunpro," which is associated with a key-based license having the serial number 1111-2222-3333-4444. This bundle encompasses two products: "Product One" (code: prodone) and "Product Two" (code: prodtwo).

To initiate the license activation for "Product One" within the bundle, the procedure involves employing the bundle license key, the code for "Product One," and the hardware ID of the relevant device. It's important to note that the bundle license functions as a mere placeholder, serving to manage the license key and LicenseUsers information.

```javascript
const axios = require('axios');
const data = JSON.stringify({
  "product": "prodone",
  "license_key": "1111-2222-3333-4444",
  "hardware_id": "test-hardware-id-1",
});

const config = {
  method: 'post',
  url: 'https://api.licensespring.com/api/v4/activate_license/',
  headers: { 
    '\'Content-Type\'': '\'application/json\'', 
    'Date': 'Thu, 28 Jan 2021 09:07:27 GMT', 
    'Authorization': 'algorithm="hmac-sha256",headers="date",signature="9Km8AoACsFfRf9+JW4gcnHMmvWoPaZIwlaZ3HeZxdgQ=",apikey="5225d654-f6e5-41f0-af90-4237a597134b"', 
    'Content-Type': 'application/json'
  },
  data : data
};

axios(config)
.then(function (response) {
  console.log(JSON.stringify(response.data));
})
.catch(function (error) {
  console.log(error);
});
```

## Working with Product Bundles with the Management API

There are two primary, product bundle-specific API calls:

- [**List Products in a Bundle**](docId:0zEABbw1wlyolDGjgsd7X) shows all products in a bundle the requesting manager has access permissions to.
- [**List Bundles for a Product**](docId\:Y39siKJXYgIAIcFyqbcii) shows all bundles for a product the requesting manager has access permissions to.

## bundle\_code

:::hint{type="warning"}
When using user based bundle licensing, it can happen that the same license user has multiple licenses for same product - one license being standalone, and another as a part of the bundle.
To make sure that License API recognizes which license needs to be used, you need to send **bundle\_code&#x20;**&#x70;aram with every call to License API.
:::

![Bundle code](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/4B3GLW6NrtNB87ddBrtwo_scr-20240402-kayu.png "Bundle code")


[title] Floating License Server
[path] License Entitlements/Floating Licenses/

:::hint{type="info"}
**Note:&#x20;**&#x56;isit our [**Floating Server Usage**](docId:0q73UcB2eH6DGGBJl-3EI) page for information on how to use our license server.
:::

In an enterprise setting, configuring all computers with a particular software license can often be inconvenient or unfeasible, particularly when the environment encompasses machines lacking internet connectivity.

To address this challenge, we present floating licensing tailored for private networks. This system hinges on a distinct floating license server that can be readily established.&#x20;

Licenses are dispensed per server, and end-user computers exclusively interact with these floating servers.

## Advantages of Opting for a Floating Server Setup

1. **Centralized License Management**: Floating servers hold the licenses instead of individual machines, simplifying upkeep and management.
2. **Redundancy and Scalability**: Floating servers are redundant and can be configured in any quantity on the network. They simply need the capability to connect with each other.
3. **Offline Capability**: In the event of a loss of internet access within the client facility network, the floating licensing functionality remains unaffected.
4. **Localized Performance and Reliability**: Floating servers are situated locally to end-user computers, ensuring minimal latency and enhanced reliability.

## Additional Considerations and Prerequisites:

- Multiple redundant floating servers can operate within the private network, necessitating their ability to intercommunicate.
- Floating server(s) necessitate initial internet access (for license activation) and periodic connectivity (to synchronize with the central server).

![LicenseSpring Floating Server Visualization ](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/F2QFCX81aA88WTYgKIshW_image.png "LicenseSpring Floating Server Visualization ")

The operational sequence for utilizing such a license unfolds as follows:

1. **Purchase and Specifications**: The customer acquires a time-limited, for instance, one-year floating license encompassing 3 activations and catering to 5000 floating users. This configuration implies that the license can be concurrently employed on 3 distinct floating servers, facilitating a cumulative 5000 simultaneous users.
2. **Floating Server Setup**: The customer establishes the floating server on up to 3 servers and embeds the license key within the server's configuration file.
3. **End-User Application Configuration**: On all end-user computers, the application necessitates configuration with just 2 parameters: the application's short-code and one or more IPs corresponding to the floating servers. There is no requirement for individual licenses. Accomplishing this is commonly facilitated through provisioning or Mobile Device Management (MDM) software.
4. **SDK Integration**: The application incorporates 2 SDK methods: **FloatingActivateLicense** (during application startup) and **FloatingDeactivateLicense** (upon application closure). These functions mirror standard **Activate** and **Deactivate** methods but diverge in their approach. Instead of connecting to the central server, they engage in license checkouts from the floating server.
5. **Automatic Ping Mechanism**: The SDK features an automated and periodic pinging system to one of the floating servers. This signaling informs the server that the current instance persists and actively utilizes the provisioned license. Should the SDK fail to ping the server within a designated interval, a solitary floating license is released. Subsequently, it can be claimed by another computer.



![Floating Server Workflow](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Fkhuf5u7IBgfKXMnSTXtX_image.png "Floating Server Workflow")


[title] Custom Fields
[path] License Entitlements/

::embed[]{url="https://www.youtube.com/embed/qvsAqdnxvmo"}

A custom field is a `key:value`  pair that is defined for a given product, which you can override for any license you issue or edit.&#x20;

## Set a License Custom Field for a License Policy

License policies are templates you can use when issuing a license, and you can specify a license custom field for any license policy. Any license issued with the policy will use the license custom field

Open the license policy editor by navigating to the license detail page > license policies, and either "add a new license policy" of by clicking on the pencil of an existing license policy.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/1HSqMZOwnTCY9IAVp9lNG_image.png)

In the license policy editor, click on "custom fields" and "select the custom fields" from the dropdown. Tick the box of any product custom field you wish to override the values for. Their values (not their names) for those selected fields can then be edited in the table. Click confirm when you are done.

:::hint{type="info"}
A notice is now displayed above the custom fields: *Setting a value here will override the default value set in the Product custom fields configuration.*
:::

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/I5Wy1EkYr3-5SI9VZKhwW_image.png)



![Selecting Custom Fields](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/-1kVdbghZ5lUh0IIVt8QA_image.png "Selecting Custom Fields")

![Editing Values for Policy](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/FzxR_od04TrvayLkJF5Ra_image.png "Editing Values for Policy")

## Edit a License Custom Field for an Existing License

Open the license detail page, and click on custom fields. You will see a table with all of the custom fields for that product, regardless whether or not they have been overridden. Click the pencil on the row for the value of the license custom field you would like to override. Click "confirm" to save the changes:

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/L_7hPYKikIPWjOVXD6t6D_image.png "Editing Custom Field")

Custom fields display labels indicating whether the value comes from the **Product Default** or is a **License-specific custom value**. Changing a field updates its type automatically if it was previously a product default.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/QOuZBQTwWHngPtOh8-knM_image.png "Product/License Custom ")

### **Resetting License Custom Field Values**

1. **Individual License Reset**&#x20;
   - For any license with **“License custom value”**, a **“Reset to product default”** button is available.&#x20;
   - Clicking it **reverts the value to the product default**, updates the label to **“Product default value”**, and removes the reset button for that field.&#x20;
   - Works consistently across **multiple custom fields**, and **bundle licenses**.&#x20;

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/l6wZh8CXSGM2d615ZTvWT_image.png)

![Editing Custom Field Value](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8rMuAeQJAnqX5sw2tyXT9_image.png "Editing Custom Field Value")

## **&#x20;During Order Creation**

- When using **custom license values** in an order, any edits to custom fields will **override the product default values**. A notification is shown to alert the user about this override.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/9VOYuihPc-DgaP5bpq3aJ_image.png)

## Product vs License Custom Fields

**Product custom fields** are defined on the product with default values. When a license is created and those default values are overridden, **license-specific custom fields a**re generated in our database. These fields are returned with the license data, allowing you to track license-specific overrides.

:::hint{type="info"}
If you add a new **custom field&#x20;**&#x74;o a product after licenses have already been created, those existing licenses **will not automatically&#x20;**&#x72;eceive the new field.
:::

To handle this, when fetching licenses via the **Management API**, LicenseSpring includes **product custom fields** in the license response. This enables you to see the differences between the product defaults and license-specific values.

For new product custom fields added after a license was created, you can retrieve them directly using the following endpoint:

:::BlockQuote
GET /api/v1/product-custom-fields/?company=\{\{platform\_company\_id}}\&product=\{product\_id}
:::

:::hint{type="info"}
If defined, the key and the value of a custom field is always returned on License Checks and License Activations. You may modify the value for any custom field for each license.
:::

For more information on defining product custom fields, please read [**Product Custom Fields**](docId\:rOHBfI4ZxLpqCjcAUk5r3).

[title] License Activation Types
[path] License Entitlements/

We define a license activation as the process of binding a license to a device.

## Ways to Activate a License

In LicenseSpring, there are 3 different activation strategies for licenses:

- Online&#x20;
- Offline&#x20;
- Air-gapped

## Which Activation Process to Choose?

### When to Use the Online Activations

Online activations are pretty straightforward and are usually the least cumbersome for the end user performing the activation. We make available a license API, and maintain a fairly comprehensive set of wrappers. In most cases, we would suggest to use online activations.

The general process for activating licenses online is that the end user would enter their license key (or email/password) into the app and initiate the activation process. This will send a request to LicenseSpring via http, which will include the license, product code, and device identifier (typically generated by the SDK). If successful, the server will return the license entitlements in a JSON, which are then parsed by the SDK (if the app is using it), allowing the software to be configured according to the license agreement.

:::hint{type="info"}
Even if a license is activated online, you can still perform offline license checks. The SDKs can be configured to update a local license file upon every successful license check.
:::

### When to Use the Offline Activations

Activating licenses sometimes cannot be done over the internet. For this situation, we maintain an offline license portal, where the SDK generates a request file. The user uploads that file on our offline portal, which will return a license file. This license file can only be used to activate by the device that specifically generated the request.

The portal can be found at [**offline.licensespring.com**]().

If the client machine activating the software license will not have access to the internet, then you can activate the license using this process.

:::hint{type="info"}
License files can be updated and sent to the end user after activation, without the end user needing to generate a new request file.
:::

### When to Use Air-Gapped Activations

Some customers have an additional requirement that once their applications have been deployed, files cannot leave the network, so they cannot use the offline activation mechanism described above.

The air-gapped license activation process entails that license policy files are deployed at the same time as software application binaries. Through a series of code exchanges generated by the LicenseSpring server and the client machine (initialization code, activation code, confirmation codes), one of the license policies can be activated for that device.

This is somewhat of a cumbersome process, so we only recommend using it to deploy software for customers that have the most stringent security requirements and where offline activations are not acceptable.

[title] Offline License Activation
[path] License Entitlements/License Activation Types/

Licenses can be activated and deactivated without the client device having access to the internet. Additionally, device variables, and consumptions will be synced with the cloud platform at the moment of deactivating licenses offline. Offline activation supports both key-based and user-based licenses.

::embed[]{url="https://youtu.be/mN4KiwQbNrI"}

:::hint{type="info"}
Subscription licenses cannot be managed using the offline portal (since subscription licenses rely on an external sytem for determining the validity of the subscription), but time-limited licenses can be refreshed.
:::

:::hint{type="info"}
The SDKs can be configured to run offline license checks. Please see their documentation for more information.
:::

## Activating a License Offline

In order to implement offline licensing in your application, please follow these steps:

1. Issue a license for the end user. The end user will enter the license in the application (either a key, or user credentials, and the SDK needs to be set to activate offline. For more information on how to activate offline, please check the extended options in your respective SDK.
2. The end user enters the license file into the app, which will unlock the application complete the binding of the license to their machine.

## Retrieving the License File From the Vendor Platform

Regardless of how a license has been activated, you can retrieve the license file from the vendor platform. This means that entitlements for a license can be modified and the license file will be updated. You can then retrieve the license file and send it to the customer:

1. Go to vendor platform and find the license
2. On the devices tab find the device where the offline license is located
3. Click on the `download license refresh file`
4. Save the `license_refresh.lic` and send it to the user.
5. The end user enters the file into the app, which will refresh local license file with new entitlements and changes

![Downlading License Refresh File](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/wqBJKxA4lI7Jdy2e3C33P_image.png "Downlading License Refresh File")

## Deactivating a License Offline

The end user can then uncouple the computer from the license, which generates a new file (a deactivation file). If they then upload this file to the portal above, the license will be released and can be used on another machine.

## Updating Consumption Values Offline

In order to update the values of total consumptions and total features consumption, you have to run the procedure of deactivating the license offline. The Vendor can always send a license refresh file to the user with new entitlements periodically.

:::hint{type="info"}
If you are working with a license that is of type consumption, or with consumption features, then the deactivation file will contain the cached consumptions which will be added to the usage information on the license on our server.
:::

## White Labeling the Offline Portal

Contact us if you would like to white label the offline portal on your own subdomain.

## Allow offline activation

By default every license can be activated using online, offline or airgap activation process.

If you want to limit your licenses to be activated only online, you can toggle the Allow offline activation checkbox on a license.

When set to `False`, the License API will not allow the license to be activated offline or airgap ( airgap being a variation of offline licensing ).



![Allow offline activation on a license](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/3ckO3GBQxRCvyuzRo2CTx_image.png "Allow offline activation on a license")

Same can be also set on a specific license policy, so when a license is created using that policy code the offlien activation setting will be applied accordingly.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/spRXiddJ4KX54g4fItEp__image.png)

###


[title] Offline Portal
[path] Portals/

URL: [**offline.licensespring.com**](https://offline.licensespring.com/)

End-users can activate and de-activate their licenses using the the offline activation method using this portal.

::embed[]{url="https://www.youtube.com/watch?v=mN4KiwQbNrI"}

## What is the Offline Portal Used for?

The offline portal is primarily useful for a few tasks, including:

- Node-locking licenses to devices that do not have a direct connection to the internet or that cannot connect to LicenseSpring via the LicenseAPI.
- Completing the deactivation process of offline node-locked licenses.
- Updating consumptions and consumption features for offline devices.

## Activating a License Offline

In order to implement offline licensing in your application, please follow these steps:

1. Issue a license for the end user. The end user will enter the license in the application (either a key, or user credentials, and the SDK needs to be set to activate offline. For more information on how to activate offline, please check the extended options in your respective SDK.
2. The end user enters the license file into the app, which will unlock the application complete the binding of the license to their machine.

## Retrieving the License File From the Vendor Platform

Regardless of how a license has been activated, you can retrieve the license file from the vendor platform. This means that entitlements for a license can be modified and the license file will be updated. You can then retrieve the license file and send it to the customer:

1. Go to vendor platform and find the license
2. On the devices tab find the device where the offline license is located
3. Click on the `download license refresh file`
4. Save the `license_refresh.lic` and send it to the user.
5. The end user enters the file into the app, which will refresh local license file with new entitlements and changes

![Downlading License Refresh File](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/wqBJKxA4lI7Jdy2e3C33P_image.png "Downlading License Refresh File")

## Deactivating a License Offline

The end user can then uncouple the computer from the license, which generates a new file (a deactivation file). If they then upload this file to the portal above, the license will be released and can be used on another machine.

## Updating Consumption Values Offline

In order to update the values of total consumptions and total features consumption, you have to run the procedure of deactivating the license offline. The Vendor can always send a license refresh file to the user with new entitlements periodically.

:::hint{type="info"}
If you are working with a license that is of type consumption, or with consumption features, then the deactivation file will contain the cached consumptions which will be added to the usage information on the license on our server.
:::

## White Labeling the Offline Portal

Contact us if you would like to white label the offline portal on your own subdomain.








[title] Reseller & Distributor Portals
[path] Portals/End-User Portal/

In LicenseSpring, the same portal is used by license managers in the classical sense (who manage the end-user's licenses), as well as resellers, or distributors.&#x20;

The only difference is the permissions set on the license manager, where some will be allowed to issue new licenses and/or create new orders.

:::hint{type="info"}
Distribution portal is available to Enterprise pricing plan only, and it can be activated on demand only.&#x20;

[**Contact us**](https://licensespring.zendesk.com/hc/en-us/requests/new) for more information.
:::

## Defining a Distributor

To give permissions to a distributor, you assign them as a license manager, and allow them to create their own orders, and add license managers to that order, who will act as resellers.&#x20;



![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/MrWJu-e7Epf08BlgE5-8g_image.png "Adjusting To Assign Distributor Permissions")

When they log in to the user portal, there will be a few changes:

- A new tab in the left will allow them to create a new order.
- On an order detail a new "License Managers" tab will appear, where they can use it to add new license managers to an order (such as a reseller).

![Create Orders through the Distributor Portal](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/I5sMYRyWZYifGQbnRD_xT_image.png "Create Orders through the Distributor Portal")

## Defining a Reseller

The resellers will be license managers who will be allowed to issue new licenses within orders that they have been assigned to, but not allowed to create new orders.

![Adding License Manager](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/qRkuy4QN_ztFjwcbg-BTV_image.png)

You can then set which products and which license policies for those products the reseller is allowed to issue licenses for.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/76GdqUGp6duEFR3rB5Jcl_image.png)



![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/sLGUKjEDRATni_uCEr4X9_image.png "Add Products and Select Enabled License Policies")

When the reseller logs in to the user portal, they will be able to issue new licenses for orders they have been assigned to:

![Issuing New Licenses](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/qWZc91zu2pplLqYhXwR55_image.png "Issuing New Licenses")


[title] Integrating SDK and Configuring License Fulfillment
[path] Getting Started/

## Integrating the SDK or API in Your Application

We offer SDKs for C++, C#, Java, Swift, Python, GO, Nodejs and Objective-C, allowing seamless integration with your application. For more detailed information on the SDKs and integrations, please refer to our [**SDKs**](docId\:bEjxOe8QzpUi-uw_8bsta).

For all other projects, detailed instructions on utilizing our APIs can be found here:

- [**License API**](docId:35HkSz8vrz5Kpu1h8EHqb)
- [**Management API**](docId\:abk8afS7gBMtujL_Rd_4p)

Furthermore, our SDKs are equipped with sample apps and header files to facilitate seamless integration.&#x20;

Should you require assistance or have any questions, please don't hesitate to [**submit a customer support ticket**](https://licensespring.zendesk.com/hc/en-us/requests/new). **We are here to help!**

## Configuring License Fulfillment&#x20;

LicenseSpring offers multiple methods to generate and dispatch license keys, catering to your specific needs. If you generate a low volume of licenses (e.g., a few keys per month), manual generation within the platform might be suitable for you.

Here are the implementation instructions for generating license keys manually or through various integrations:

1. Generating keys [**Issuing New Licenses**](docId\:fedDg9WixsYbHadHXYoL0)
2. Utilizing the [**License API**](docId:35HkSz8vrz5Kpu1h8EHqb) and [**Management API**](docId\:abk8afS7gBMtujL_Rd_4p)
3. Utilizing the [**Shopify**](docId\:KMIawJSvFgKP4vEy4-cYJ)**&#x20;Plugin&#x20;**(maintained by a 3rd party)
4. Integrating with [**FastSpring Classic Store**](docId:6mqWFZBE6S8clLJYMdLen)
5. Integrating with [**FastSpring Contextual Store Old**](docId\:Klcl4d0l8lVEJS-FGEvzK)&#x20;
6. Integrating with [**Salesforce**](docId:1TJgk6xKroiN2_FLsKtVv)
7. Integrating with [**Stripe**](docId:-ny0MceSD689_M1OPs5YS)

Choose the method that best aligns with your requirements to efficiently manage and deliver license keys using LicenseSpring.

[title] Settings
[path] Vendor Platform/


[title] License Users
[path] Vendor Platform/

This page lists all **license users that have been added to a LicenseSpring accont**. a License User typically is added to LicenseSpring at the moment they are assigned to a given license A license user represents an individual who can access and use a product under a user-based licensing model.

![License Users Page](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Aogob3ddfwBhmgSZcp964_image.png "License Users Page")

## Searching for License Users

You can search for a license user to find all the licenses they are assigned to. The following search criteria are supported:

- First Name
- Last Name
- Email
- Phone Number

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/2bv5Xat59f1EGr1ZT1-TM_image.png "License User's Search Options")



## Individual License User Information

After selecting a license user, you will see the **User Details&#x20;**&#x73;creen, where you can inspect the user’s information across three main sections: **licenses, devices, and user groups**.&#x20;

### Licenses Tab

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/_0TQEsKnAbhQU5inoZTWu_image.png "Licenses Tab")

- This table displays all licenses currently assigned to the user. You can view key details including:
- **Created On:** Date and time the license was issued.
- **User:** The assigned user’s email.
- **Product:** Name of the licensed product.
- **Product Features:** Specific features included in the license.
- **License Type:** Type of license (e.g., perpetual, subscription).
- **Expiration Date:** When the license will expire (if applicable).
- **Times Activated:** Number of times the license has been activated.
- **Is Trial:** Indicates if the license is a trial version.
- **Status:** Current state of the license (e.g., active, inactive).



:::hint{type="info"}
**Initial Password:** This is the password automatically generated when a user is first added to LicenseSpring. Users are prompted to reset it upon first login.
:::

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/CiiGYZSvKZzyqzzboJxqV_image.png "Initial Password")

### Devices Tab

Here you can view detailed information about each device where the user has activated a license. The table contains:&#x20;

- **Details:** General information about the device itself.(IP address, host name, SDK version&#x20;
- **Type:** Type of device.
- **Hardware ID:** Unique identifier for the device.
- **Last Check:** The most recent time the license was verified on this device.
- **Status:** Current status of the license on the device.
- **Device Variables:** Any custom variables stored for this device&#x20;
- **Floating in Use:** Indicates if the license is currently active in a floating license pool.
- **Borrowed:** Shows if the license has been borrowed from a floating pool.
- **Floating Last Check:** Timestamp of the last floating license verification.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/6188dF5j2j5D1Vid-AELX_image.png)

### User Groups Tab

- Lists any **user groups** the user belongs to.
- User groups help simplify license management. On the User Group page, you can easily assign users, allocate licenses, and designate license managers.&#x20;
- ![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/JZmY35u4ebSyIlb7-QHmc_image.png "User Groups tab")

## Add a new License User

Most users are automatically added to LicenseSpring when assigned a license. If a user does not yet exist in the system and you plan to assign them to a license later, you can also add them manually:&#x20;

1. Click **Add License User**
2. Enter user details (name, email, phone number and Metadata JSON.)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/casBeE42wp61ObvEA-2Ji_image.png "Add License User")

- After clicking the **Confirm&#x20;**&#x62;utton, the user will receive an email containing their initial password.&#x20;



:::hint{type="info"}
To learn more about user groups, including how to **create them&#x20;**&#x61;nd **manage licenses**,**&#x20;users**, and **license managers**, please click the link.[**&#x20;User Groups**](https://docs.licensespring.com/user-groups)
:::

:::hint{type="info"}
**User-Based Licensing &#x20;**&#x20;Learn how user-based licenses work and review best practices in the[**&#x20;User-Based Licensing Guide**](https://docs.licensespring.com/sdks/tutorials/licensing-scenarios/user-based)
:::


[title] License Policies
[path] Product Configuration/

## What Is a License Policy?

::embed[]{url="https://www.youtube.com/watch?v=MqpjJy_2LXw"}

A license policy is a templating feature within LicenseSpring to easily issue a new license according to a preset of entitlements. There are a few benefits to using license policies:

- **Less error-prone**: If you defined dozens of features and custom fields, and primarily sell your product in a few combinations of these, then license policies help you avoid configuration mistakes
- **Easier to integrate with other systems**: Let's say you would like to sell licenses of your app through Stripe, the license is time limited, and has 3 of a product's 7 features, with a max activations of 5. Instead of setting up your order webhook with each of these entitlements defined on your Stripe Integration, you can just define a license policy and select it in Stripe.

:::hint{type="info"}
Every product has at least 1 license policy, and there must be at least 1 default license policy.
:::

:::hint{type="warning"}
A License Policy is only a template. Once a license is issued, you can modify certain parts of the entitlements (eg: extend the validity period, change the max activations etc.).
:::

## How to Create a License Policy?

Navigate to the license detail page and click on "License Policies" and then "Add license policy"

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/F_MveRLf5w1eslb8BqCWH_image.png)

On the License Policy editor, the required fields are that you give the license policy a name and a code. All other parameters are optional.

![Setting Values for License Policy](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/7NyGlwPja3vYIjVXvXiXs_image.png "Setting Values for License Policy")

## What Fields Can Be Set for a License Policy?

### Policy Values

- `Name` Required
- `Code` Required, immutable
- `License type` Required, can be Perpetual, Time-limited, Subscription, or Consumption
- `Is trial` Optional, Boolean determining whether the license issued is a trial license
- `Max activations` Must be a Positive INT
- `Allow unlimited activations` Boolean
- `Has device transfer limit` Whether you wish to control the number of times a license can be moved from one device to another
- `Prevent virtual machine` Boolean value sent to eht SDKs to detect and block apps running in Virtual environments
- `Offline Floating license` Boolean, setting entitlements for a floating server that is deployed.
- `is floating cloud` Boolean setting concurrency over http
- `Enable Maintenance period` Set a maintenance window which starts counting after the initial activation of the license.

### Product Features

You can add or remove product features to the license policy. For consumption features, you can set different values for `Max consumptions` , `max overages`  and for `periodic resets` .

### Custom Fields

You can select the values of the product custom fields you wish to override in the dropdown.

:::hint{type="info"}
The Policy name and the policy code are required fields. You cannot change the policy code once the license policy is defined.
:::

## How to Use License Policies?

### Using License Policies to Issue Licenses Manually Through the Vendor Platform

Through the vendor platform: navigate to Licenses > Issue Licenses. Add order and customer information and hit next. Click "Add product" and you will see the product selector screen. From here, you can choose which license policy to use when issuing a license for that given product:

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/J2qRJU7ANczeaUVFz4Wi1_image.png "Selecting License Policy")

If you wish to use the License policy as a starting point when configuring the license you are issuing, then enable `Use custom license values` . The editor will start with all of the options configured in the license policy:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/sHL5BMkT2yuOdJYVqyQxH_image.png)

### Using License Policies to Issue Licenses through Stripe integration

License policy code can be added as a custom attribute to the Stripe product price so that any subscription created using this price will create licenses using that specific license policy.

More details can be found [**Stripe Integration**](docId\:JHfnp0VPixrFxBR3OQtjx) .

### Link License Policy to the License

LicenseSpring supports tracking and exposing the license policy code associated with a license. This enhancement provides better traceability and improves visibility into which policy was used when a license was created.

When a license is created using a specific license policy, the policy identifier is stored and made available via both API responses and the user interface.

**License Creation**

If a license is created by specifying a license policy the system will:

- Persist the `license_template_id` ( policyID ) at the license level.
- Ensure this value remains associated with the license throughout its lifecycle.

This can be achiveded when creating a license using Management API and sending a specific `license_template_id` parameter as a license entitlement field.

Alternatively, if is also assigned to a license by default when created using platform.

If custom values toggle is not used, the selected default policy will be assigned to a licenses.

![Link License Policy to a License using platform](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/KVugq4s8nd-0rR8KA9DCY_image.png "Link License Policy to a License using platform")

In the Vendor platform, the License details view will include a display of the linked License policy.



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/SnugCK8RtwR2yXezJ_Pwx_image.png)

This ensures transparency regarding how license terms were determined, supports auditability by maintaining a clear link between licenses and their policy definitions and enhances usability for vendor teams managing complex policy configurations.

### License Policy as a SKU

To improve product structuring, searchability, and traceability, LicenseSpring introduces a mechanism to treat License Policies as **SKUs**. A new boolean configuration enables policies to behave like immutable identifiers tied to specific licensing terms.

This enhancement supports workflows where license policies represent pre-defined commercial SKUs and must remain consistent once assigned to licenses.

**SKU Behavior Toggle**

A boolean field exists in the License Policy configuration:

- **Field**: `is_sku`
- **Purpose**: When enabled, this marks the policy as a **SKU-like policy**.
- **Effect**: Licenses issued with such policies behave as if associated with a commercial SKU.

When a license is created directly using a policy marked as `is_sku = true`as defined section above:

- The policy’s identifier and SKU flag are stored at the license level.
- This association ensures consistent behavior and enables future queries or logic based on SKU grouping.

To ensure SKU consistency:

- Policies marked as SKU become immutable after they are created.
- Attempts to change policy settings post-issuance will be rejected or restricted to prevent SKU drift.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/WdP95mhX6hHWjwoiiusAB_image.png)

License search functionality includes option `Search by license policy code` and results include all licenses issued using specific policies, and in this case also enabling behavior similar to product SKU filtering in e-commerce or inventory systems.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/DDw-lHydik0bXLHnxYCMc_image.png)

Using SKU license policies enables product-based license tracking and reporting. It also prevents accidental modifications to SKU-critical policies, streamlines license discovery through SKU-style search filters and ensures operational consistency in SKU-driven sales and deployment processes.

[title] End-User Portal
[path] Portals/

::embed[]{url="https://www.youtube.com/watch?v=Q-rP0zq-9WQ"}

:::hint{type="info"}
License users and/or license managers cannot update the customer details.

Currently possible only by using Management API [**here**](https://app.archbee.com/docs/FbT_Z5Cu33D-LVZx1fRkU/AHB3EG-1EquDJMbts-3I3).&#x20;
:::

The intermediary user portal is accessible to those situated between the software vendor and the end user, enabling them to be identified and carry out their designated roles.

## Languages Available in the User Portal

At the time of this writing, the user portal has been translated into English, Spanish, French and German. It can translate it into other languages upon request.

## Actions That Can Be Performed Through the User Portal

By default, it is possible to perform the following actions through the user portal:

- Assign/un-assign users to a user-based license
- Issue licenses and create orders (used like a reseller/distributor portal)
- Reset licenses and devices
- Reset end-users' credentials

It is also possible to customize the permissions of users to remove any of the above and add any of the following:

- Borrow licenses
- Create bundle orders
- Create orders
- Issue licenses
- Revoke devices

It is also possible to configure this portal as a [**Reseller & Distributor Portals**](docId\:NmIbAPRmvlmqOsPZbnsI0).

![User Portal View once Logged In](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/7vUYkT9SuunBwVUDjLlah_image.png "User Portal View once Logged In")

## Key Concepts for the User Portal

## Our Data Model:

Before issuing a license, it might help to know how our data model is organized:

![Vendor Platform Data Model ](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/k8PdYvrZ9URtZGiKIN-Se_image.png "Vendor Platform Data Model ")

- A **license&#x20;**&#x63;an belong to an order. You can have 0 to many licenses for an order.
- An **order&#x20;**&#x63;an belong to a customer. You can have 0-to-many orders for a customer.
- A **customer&#x20;**&#x63;an belong to an account. You can have 0-to-many customers for an account.

:::hint{type="info"}
A license will belong to an order. If you do not specify an orderID, a random orderID will be generated
:::

If you do not specify an orderID, a random ID will be generated for you. Orders do not need to belong to customers. However, it can be useful to have this association for analytics, or for customer support, for example.

:::hint{type="info"}
A license manager is a user that is assigned to an order who can then log in to the user portal. Depending on their permissions, they can perform various edits to the licenses within the order.
:::

## Logging in to the User Portal

License managers log into the user portal.

They need to enter their email / password and the Company ID in order to Log in.

:::hint{type="info"}
The user portal's URL can be customized to a vendor's subdomain, where then there is no need to enter company ID. Contact us for more information.
:::

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Kw07ztzIQzcuQcJ24UWtx_image.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Kw07ztzIQzcuQcJ24UWtx_image.png" size="56" width="506" height="554" position="center" caption="User Portal Login" alt="User Portal Login"}

:::hint{type="info"}
The company code can be found in the vendor platform under settings. The company code is also sent via email notification when a license manager is assigned to a license, provided an email notification was set up and configured for this purpose.

![Company Code Location](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/15LrQX59NG7qhNUDeyQ3x_image.png "Company Code Location")
:::

## Customizing  the User Portal

In the Vendor Platform, you can customize some parts of the user portal, such as:

- The color scheme and the logo
- Allowing end users may reset licenses in the user portal
- Allowing end users to reset licenses
- Displaying product download links

To customize the portal, log in to the Vendor Platform, and click on Settings > Portal configuration

![Portal Configuration](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/sLfRSwb2p-ZQ-B4BFfcEs_image.png "Portal Configuration")




[title] Public API Metadata
[path] License API/

## API Well-Known Endpoint

The /.well-known endpoint is a **public metadata endpoint** designed to help clients, SDKs, and integrations automatically discover important configuration information about your API.

By accessing this endpoint, developers and tools can programmatically retrieve:

- The **base URL** for API requests (api\_base\_url)&#x20;
- The **supported API versions** (supported\_api\_versions) and default version  (default\_api\_version)&#x20;
- The **current API release version** (version)&#x20;
- The **environment** (e.g., dev, staging, prod)&#x20;
- A **public key or certificate** for secure communications (pub\_key)&#x20;
- A **list of available API endpoints** and their HTTP methods (endpoints)&#x20;

This eliminates the need for manual configuration or hardcoding these values into client applications. This endpoint is publicly accessible and requires no authentication.

:::hint{type="info"}
**Use Case Example:&#x20;**&#x57;hen a new SDK initializes, it can first call  /.well-known  to learn the API base URL, supported versions, and endpoints, ensuring that all requests are correctly configured without requiring manual updates in the code.
:::

:::ApiMethodV2
```json
{
  "name": "/api/v4/.well-known",
  "method": "GET",
  "url": "/api/v4/.well-known",
  "description": "Returns static or generated JSON with environment, version, and endpoint details.",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "lgiQYYjqoVvkDPTsins5w",
        "language": "none",
        "code": "---------------------NONE--------------------",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "lgiQYYjqoVvkDPTsins5w"
  },
  "results": {
    "languages": [
      {
        "id": "IvlrYac4TqrOaKfa6Ly80",
        "language": "200",
        "code": "{\n  \"api_base_url\": \"http://api.licensespring.com/api/v4\",\n  \"environment\": \"dev\",\n  \"supported_api_versions\": [\"v4\"],\n  \"default_api_version\": \"v4\",\n  \"version\": \"4.1.34\",\n  \"timestamp\": \"2025-10-28T10:32:21.580Z\",\n  \"pub_key\": \"-----BEGIN CERTIFICATE-----\\nMIIFrjCCA5YCCQDXhLQ....0ExGTAXBgNVBAgT-----END CERTIFICATE-----\",\n  \"endpoints\": [\n    {\"method\": \"GET\", \"url\": \"/api/v4/.well-known\"},\n    {\"method\": \"GET\", \"url\": \"/api/v4/trial_key/\"},\n    {\"method\": \"POST\", \"url\": \"/api/v4/activate_license/\"},\n    {\"method\": \"POST\", \"url\": \"/api/v4/activate_bundle/\"},\n    {\"method\": \"POST\", \"url\": \"/api/v4/activate_offline/\"},\n    {\"method\": \"POST\", \"url\": \"/api/v4/activate_bundle_offline/\"},\n    {\"method\": \"POST\", \"url\": \"/api/v4/deactivate_license/\"},\n    {\"method\": \"POST\", \"url\": \"/api/v4/deactivate_offline/\"},\n    {\"method\": \"POST\", \"url\": \"/api/v4/deactivate_bundle/\"},\n    {\"method\": \"POST\", \"url\": \"/api/v4/deactivate_bundle_offline/\"},\n    {\"method\": \"GET\", \"url\": \"/api/v4/check_license/\"},\n    {\"method\": \"GET\", \"url\": \"/api/v4/check_license_feature/\"},\n    {\"method\": \"POST\", \"url\": \"/api/v4/add_consumption/\"},\n    {\"method\": \"POST\", \"url\": \"/api/v4/add_feature_consumption/\"},\n    {\"method\": \"GET\", \"url\": \"/api/v4/get_device_variables/\"},\n    {\"method\": \"POST\", \"url\": \"/api/v4/track_device_variables/\"},\n    {\"method\": \"GET\", \"url\": \"/api/v4/versions/\"},\n    {\"method\": \"GET\", \"url\": \"/api/v4/installation_file/\"},\n    {\"method\": \"POST\", \"url\": \"/api/v4/floating/borrow/\"},\n    {\"method\": \"POST\", \"url\": \"/api/v4/floating/release/\"},\n    {\"method\": \"POST\", \"url\": \"/api/v4/floating/feature_release/\"},\n    {\"method\": \"POST\", \"url\": \"/api/v4/change_password/\"},\n    {\"method\": \"GET\", \"url\": \"/api/v4/customer_license_users/\"},\n    {\"method\": \"GET\", \"url\": \"/api/v4/sso_url/\"},\n    {\"method\": \"GET\", \"url\": \"/api/v4/products/\"},\n    {\"method\": \"GET\", \"url\": \"/api/v4/product_details/\"},\n    {\"method\": \"GET\", \"url\": \"/api/v4/user_licenses/\"},\n    {\"method\": \"GET\", \"url\": \"/api/v4/device_licenses/\"},\n    {\"method\": \"GET\", \"url\": \"/api/v4/oauth_url/\"},\n    {\"method\": \"GET\", \"url\": \"/api/v4/check_bundle/\"},\n    {\"method\": \"POST\", \"url\": \"/api/v4/webhook/order/\"},\n    {\"method\": \"GET\", \"url\": \"/api/v4/webhook/license/\"}\n  ]\n}\n\n",
        "customLabel": ""
      },
      {
        "id": "5V8XkUYOEx5twDfwfYBBl",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "IvlrYac4TqrOaKfa6Ly80"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "response": [
    {
      "name": "api_base_url",
      "kind": "optional",
      "type": "string",
      "description": "Base URL for the API.\n"
    },
    {
      "name": "supported_api_versions",
      "kind": "optional",
      "type": "array",
      "description": "List of API versions supported.",
      "children": []
    },
    {
      "name": "default_api_version",
      "kind": "optional",
      "type": "string",
      "description": "Default API version to use.",
      "children": []
    },
    {
      "name": "version",
      "kind": "optional",
      "type": "string",
      "description": "Current API release version.",
      "children": []
    },
    {
      "name": "environment",
      "kind": "optional",
      "type": "string",
      "description": "Current environment (e.g., dev, staging, prod).\n",
      "children": []
    },
    {
      "name": "timestamp",
      "kind": "optional",
      "type": "string",
      "description": "UTC timestamp when the response was generated. string (ISO-8601 UTC)\n",
      "children": []
    },
    {
      "name": "pub_key",
      "kind": "optional",
      "type": "string",
      "description": "Public certificate/key for API communication.",
      "children": []
    },
    {
      "name": "endpoints",
      "kind": "optional",
      "type": "array",
      "description": "List of all available API endpoints with method and path.",
      "children": []
    }
  ],
  "autoGeneratedAnchorSlug": "apiv4well-known",
  "legacyHash": "8XEV6-3soscJgrtC5MOU6"
}
```
:::

:::hint{type="success"}
Provides public configuration metadata so clients and SDKs can automatically discover API details like base **URL, supported versions, and endpoints.&#x20;**
:::


[title] Two-Factor Authentication (2FA)
[path] Vendor Platform/Settings/

Enabling Two-Factor Authentication (2FA) enhances the security of your account by requiring a second layer of authentication. This page provides instructions on how to enable 2FA for all platform users on the vendor account and how to complete the 2FA setup upon logging in.&#x20;

## Enable 2FA for platform users in the Vendor Platform&#x20;

### 1. Navigate to Settings

- Go to the `Settings` section in the sidebar and click on the `Preferences` tab.

![Preferences Tab](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/bkFJvwloJ_aDVLX1h_32b_image.png "Preferences Tab")

### 2. Enable 2FA Requirement

- Scroll down to the `Security` section.
- Click on the `Enable 2FA` button to make 2FA mandatory for all users within your company account.

![Enable 2FA](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/v3TbgQQD_t3pHCOlWC_DT_image.png "Enable 2FA")

### 3. Save Changes

Once 2FA is enabled, it will be required for all users during their next login.

## Complete the 2FA Setup When Logging In&#x20;

The next time you log in, you’ll be prompted to configure 2FA for your account. Follow these steps:

### 1. Install a Mobile Authenticator App

- Download and install one of the supported authenticator apps on your mobile device:
  - Google Authenticator
  - Microsoft Authenticator
  - FreeOTP

### 2. Scan the QR Code

- Open the authenticator app and scan the QR code displayed on the screen.

::Image[&#xA;&#xA;In the One-time code field, enter the code generated by your authenticator app.&#xA;Provide a Device Name]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/1bNcPNLvCoulcYFIhgyle_image.png" signedSrc size="50" width="800" height="1450" position="center" caption="2FA QR Code Setup" alt="2FA QR Code Setup"}

- If you’re unable to scan the QR code, click the `Unable to scan?` link for alternative setup instructions.

### 3. Enter the One-Time Code

- In the `One-time code` field, enter the code generated by your authenticator app.

### 4. Provide a Device Name&#x20;

- In the `Device Name` field, add a label to help identify the device you are setting up for 2FA (e.g., “Work Phone”).

### 5. Sign Out from Other Devices (Optional)

- By default, the option to `Sign out from other devices` is checked. You can uncheck this if you want to remain signed in elsewhere.

### 6. Submit and Complete Setup

- Click the `Submit` button to finalize the 2FA setup for your account.
- You will now be required to use your authenticator app for future logins.






[title] Product Configuration
[path] /

![Products within your LicenseSpring account](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8bQR11qxZO_AnW9FKBFWx_image.png "Products within your LicenseSpring account")

## What Is a Product?&#x20;

In LicenseSpring, a product is what you can issue licenses for. This is usually a software application, but it could be an operating system, or maybe even a hardware device.

In order to issue and manage licenses, you will need to have a product to issue and licenses for.

## Initializing a Product

To Create a new product, click on "Configure Products" on the left-hand navigation, and then "Add a new product" on the Product summary view.

![Creating New Product](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8YNFUI1y1VKGwqCjQq8Gc_image.png "Creating New Product")

Next, enter a `Product name` , and a `Product code` . The Product name is only used in the vendor platform. The Code will be used in many places, such as when making API calls to validate a license, or when issuing a license from an e-commerce platform. The `Product name`  can change, but the `Product code`  cannot change.&#x20;

:::hint{type="info"}
The product code must be unique, and be comprised of only lower-cased alpha-numeric characters. No spaces, no special characters are permitted.
:::

Select the `Authorization method`  for your product. We support both `key-based`  and `user-based` licenses.

:::hint{type="warning"}
A product can be either key-based or user-based. You cannot change the authorization method once the product has been initialized.
:::

You can specify is the `Product has a trial period` , if selected, you can set the default validity period of trial licenses that are issued

`Floating timeout`  refers to the default heartbeat for ay floating licenses issued. Note that this can be overridden for any license that is issued.

Lastly, you can specify an initial release version of the product by ticking the box `Product has file` .

![Inserting Product Information](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/SvBaRgeWj_01NIjitnWqC_image.png "Inserting Product Information")

Click `Next` review the details you entered for the product initialization and click `Create Product` . Your new product will now appear in the product summary screen.

![Create New Product](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/YiNk1yrvG43wxjc0VS7yD_image.png "Create New Product")

![Product List](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/dxoTb9eYe4gbjY8_8-7Ub_image.png "Product List")

Click anywhere in the row containing your product name, and you will be directed to the product detail page.

![Product Detail Page](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/qi6qM4M8868moJHBroc1E_image.png "Product Detail Page")

## Disable a Product

Disabling a product will prevent issuing licenses for that product. The Status on the Product List View will be changed from `Active`  to `Disabled` .&#x20;

A Disabled product can be re-enabled at any time, and it will still appear in the Product List. You can still edit the product, such as add features and custom fields, as well as License Policies.

To Disable a Product, go to the product detail screen, and click "disable product":

![Disabling a Product ](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/BwOXJYn24mFnLSutMD-5a_image.png "Disabling a Product ")

It will now appear as disabled on the Product List View:

## Archive a Product

Archiving a Product will remove it from the product list, and will disable it if it is enabled.

You cannot modify archived products, but you can `Reactivate` an archived product.

You can find your archived products in their own tab on the Product List. Click on the "Reactivate" button on the respective row if you would like to Reactivate a product.

![Archieved Product List](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/dhqMBhcUfbpXGRnWaEWxC_image.png "Archieved Product List")


[title] License Note
[path] License Entitlements/

License notes are additional information or comments that can be included by license managers in the back-end system for individual licenses.&#x20;

These notes serve as internal annotations or reminders associated with a specific license and are typically not visible to the end-users or license holders.

License managers have the option to add license notes to provide supplementary details, instructions, or special considerations related to a particular license.&#x20;

These notes can include important information such as license activation instructions, specific usage guidelines, license expiration dates, customer-related details, or any other relevant notes that assist in the management and administration of the licenses.


![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/12lt_-HxxYLJa8xUxtPc__image.png "License Note Field")

License notes serve as a communication tool within the license management system, allowing license administrators or support personnel to include additional context or instructions for a license.&#x20;

These notes are primarily intended for internal use and help facilitate effective license management, tracking, and support.

Through license notes, license managers can enhance their ability to manage and maintain licenses effectively, ensuring that important information and instructions are readily available within the back-end system.




[title] License Manager Guide
[path] Portals/End-User Portal/

LicenseSpring provides an **end-user portal** designed to improve the interaction between software vendors and their customers. This portal allows authorized users, known as **License Managers**, to manage licenses and devices effectively. Whether you are managing licenses for a team or distributing them across different users, this guide will walk you through the essential functions of the LicenseSpring user portal.

## User Roles

The user portal is designed with distinct roles in mind, ensuring that only authorized personnel have access to specific features:

- **License Managers**: Users who manage licenses for a group or organization. They have access to the end-user portal which allows them to perform the actions stated below, **depending on the permissions enabled**.
- **End-Users**: These are the customers or employees using the software. They do not have access to the portal, they typically have the ability to activate licenses and view license details but not any administrative actions.

## Permissions Overview

Permissions in the LicenseSpring portal can vary depending on your role, but here are some of the key functions available based on your access level:

- **Assign/Unassign users**: This allows License Managers to assign or remove end-users from user-based licenses. Useful for organizations managing multiple users and needing to quickly transfer access between individuals.
- **Reset Licenses or Devices**: Resetting a license or device allows a License Manager to reissue the license or free up activations tied to specific hardware, helping ensure compliance with license terms.
- **Borrow Licenses**: This feature allows users to take a license offline temporarily, ideal for situations where internet access is unavailable. The borrow functionality is configurable and can be set by the License Manager based on need.
- **Issue Licenses**: This is typically used by resellers or distributors who need to generate licenses on behalf of end-users. The License Manager can create and allocate licenses as per customer demand.
- **Revoke Devices**: This allows a License Manager to remotely revoke access for devices that are no longer authorized to use the software.
- **Reset End-User Credentials**: Gives License Managers the authority to reset passwords or other login credentials for end-users, allowing seamless access to the software if users are locked out.
- **Create Bundle Orders**: For organizations offering bundled products or services, this permission gives License Managers the ability to create orders containing multiple licenses in one transaction.
- **Create Orders**: This permission allows License Managers or authorized end-users to generate new orders directly from the portal, which includes configuring licenses for new or existing users.
- &#x20;**Edit Customer:** Allows License Managers to update customer information on existing orders. Useful for correcting or modifying customer details without creating a new order.
- &#x20;**Edit License:&#x20;**&#x41;llows License Managers to modify existing license details and use the *Use Custom Values*toggle when creating orders, enabling adjustments to license entitlements beyond the default policy values.
- &#x20;**Edit License Custom Fields:&#x20;**&#x41;llows License Managers to edit custom fields on existing licenses and set custom values during order creation. Useful for applying customer-specific information or metadata to a license.
- &#x20;**Edit License Product Features:&#x20;**&#x41;llows License Managers to modify product features on existing licenses and configure features during order creation. Helps adjust feature-level access without changing the underlying license policy.

### Default Permissions For End-Users

By default, as an end-user you are able to perform the following actions through the user portal:

- Add License Managers to an Order
- Assign/Unassign License Users
- Change License User’s Passwords
- Reset Licenses and Devices

### Optional Permissions to Add

Some Vendors may change the default permissions granted to License Managers by adding or removing certain permissions. Additional permissions include:

- Borrow Licenses
- Create Bundle Orders
- Create Orders
- Revoke Devices
- Issue Licenses

## Using the Portal

The LicenseSpring user portal is designed to be intuitive, allowing License Managers to perform essential actions related to licenses, orders, and users. Below is a detailed guide on how to use the core functionalities of the portal effectively.

### Logging In

To login, License Managers must enter their email/password combination and company ID in order to log in, but if the user portal URL has been customized to a vendor’s subdomain then there will be no need to enter this company ID. The login screen for a non-whitelisted URL is shown below:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Ma0hEMCD5-MkDqUQnSxtJ_image.png "End")

The company code, email and password will all be provided to you by the software vendor, as it is set through their portal. 

### Look Up a License

Licenses can be looked up on the end-user portal in a variety of ways, including by:

- License user email
- License key
- Order ID
- Product name
- Device hostname

To do so, click \`**Licenses**\` on the left-hand side of the portal then use the search bar at the top of the page as shown below:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/5Pe-khfcT4550gUUJrc82_image.png "Looking up a License")

:::hint{type="info"}
LicenseSpring supports key-based and user-based licenses, visit [**Activate a Key-Based License**](docId\:fF0ezEWc-EOi3l8NypEh6) and [**User-Based Licensing**](docId\:xEPx04M3OH_F6s8ylf6mZ) for more information on the differences between the two
:::

### Look Up an Order

The workflow for looking up an order is very similar to looking up a license and can be searched only by order ID. First, get to the \`**Orders**\` page on the left-hand side then use the search bar, as seen in the following screenshot:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/xUPWNkEYcwfxeP_foTYnE_image.png)

### Assign a User

To assign a user to a license, click on the specific license on the \`**Licenses**\` page, then go to the \`**License users**\` tab on the license details page. From here you can assign the user by clicking the blue \`**Assign license user**\` button, shown below:



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/DK8OWnBceHpDaGNh4jBdx_image.png "Assigning User")

### Unassign a User

Once this user has been assigned to a license, you can then remove them by clicking on the button on the far right under \`**Actions**\`, then clicking remove:



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Y3_8P3jdDuDg_49XEkWXT_image.png "Unassigning Us")

### Change a User’s Password

License Managers can change a license user’s password under the same \`**Actions**\` button that is shown above, then by clicking the \`**Change password**\` button:



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/yfY471SQDLdOcVg0sBds3_image.png "Chancing User's Password")

### Reset a Device

To reset a device, head to the \`**Licenses**\` page then select the license that the device has been activated on. Click the \`**Devices**\` tab then the \`**Actions**\` three-dot button, then click \`**Reset**\` as shown below:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/bBX5wc4VzTqfaO2ZTCt_x_image.png "Resetting Device")

### Reset a License

Resetting a license includes navigating to the \`**Licenses**\` page, then clicking the red \`**Reset license**\` button:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/7bQXebvY3x6_xD--yn34A_image.png "Resetting Licence")

:::hint{type="info"}
Resetting a license refers to adjusting the license values back to their defaults (i.e. resetting consumptions, activations, etc).
:::

### Issue a License

To issue additional licenses, navigate to the \`**Orders**\` page on the left-hand side, select an individual order then click on the \`**Licenses**\` tab. From here, click \`**Issue new Licenses**\` as shown below, then select more licenses to issue within this order.



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/_FLrsSqIcU7cdepSm65nH_image.png "Issuing New Licenses")

### Borrow a License

To borrow a license, the license must first be activated on a device then it can be borrowed by going to the \`**Devices**\` tab on the \`**Licenses**\`  page. After clicking on the \`**Actions**\` button on the far right you will see the opportunity to \`**Borrow**\` the license, as shown below:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/RfSUDVljfE0JcVi-4z33c_image.png)

### Create an Order

To create an order, click the \`**Create order**\` button on the left-hand side, then provide the order ID, order reference, and customer details on the following page:



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ZNFVAqxkT3wg_iX861Yq-_image.png "Creating Orders")

On the next page, you will be prompted to select the product(s) to add to the order. First, you have the option to select an individual product, or a product bundle (which is a package consisting of multiple products).

You will next select the product or product bundle (as well as the license policy, which is how different values for a license are set, such as max activations, max license users, whether it is a trial, etc.). These license policies are all created by the software vendor and are not your responsibility, as the License Manager. After confirming the order details, the order will be created.

If the required permissions are in place:
Only users who meet **all** of the following conditions can create bundle orders in the User Portal:

- The user is logged in as a **License Manager**
- The user has permission to **create orders**
- The user has permission to **create bundle orders**
- The user has **product-level permissions for every product included in the bundle**

:::hint{type="info" indent="2"}
A frequent reason bundle order creation fails is **missing product permissions**.

For example:

- The product bundle **user-bundle2** contains two products:
  - user-prod
  - user2
- If you only have permission for user-prod but **not** for user2, you will **not** be able to create the bundle order.
:::

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/gtDVgqPrst2R3kYVxenf6_license-managers-permisions.png)

1. The License Manager will see the option to select a **configured product bundle** when creating an order in the User Portal.
2. The License Manager can issue the bundle order in a single action.
3. Once the order is successfully created, the User Portal retrieves and processes the bundle details.
4. All individual licenses included in the bundle are displayed correctly, in the same way they appear on the main platform.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/CxPmwtEV6C1BqdcXLKuFE_create-order-for-product-bundle.png "Create Order for Product Bundle")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/83g_Ar7BqrezEpMhFbPhP_select-product-bundle.png)



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/lcoU0zbupKezlwV697Pf-_bundle-license-license-manager.png "Bundle Order Created")

If the license manager has the **Edit License** permission, a new toggle option “Use Custom License Values” is now available during the product selection process. This allows license managers to specify custom values for licenses when assigning products. Please refer to the screenshot below for guidance.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/FKy250r4odVYK4XPAZuZK_image.png)

&#x20;When the toggle is enabled, it allows the license manager to edit and customize the license values for the selected product.



If the user has the **Edit License Product Features** permission and the product includes any features, the Product Features tab becomes visible once the license manager enables the Use custom license values toggle.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/rbEtnN4RCgs5z3yvJRshf_image.png)

:::hint{type="info"}
With the **Use custom license values&#x20;**&#x74;oggle enabled, users can edit the **Product Features&#x20;**&#x74;hey want to include in a license. They can only add features that are already available in the product; license managers do not have access to manage or create global features that are not part of the license policy.
:::



If a user has th&#x65;**&#x20;Edit License Custom Fields&#x20;**&#x70;ermission and the product contains custom fields, the Custom Fields tab will become visible once the Use custom license values toggle is enabled. Please see the screenshot below for reference.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/A6o4ut8zMVycYPV6rxVLP_image.png)

After saving, the user will be able to view the changes they made as shown below:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/1z0F2fV9wUbXTfyu_QcB8_image.png)

Users with the **Edit Customer&#x20;**&#x70;ermission can edit customer details from the Order page under the Customer tab.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Lr-W3g1fw42xmcPpDrfp-_image.png)

Users with the **Edit License&#x20;**&#x70;ermission can edit license details directly from the License page.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/9UW1LOg7rg1NdEm4nUIGz_image.png)

Users with th&#x65;**&#x20;Edit License Product Features** permission can manage product features on the License page under the Product Features tab. This includes adding, editing, and removing product features.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/y7wD1rLXcObCTRdJiUsQV_image.png)

Users with th&#x65;**&#x20;Edit License Custom Fields** permission can edit license custom fields on the License page under the Custom Fields tab.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/oy-FNua0nWkg5d2vu6vDG_image.png)

### Revoke a Device

To revoke a device, go to the \`**Licenses**\` page on the left-hand side then click on the \`**Devices**\` tab to see devices associated with the license. Then click the \`**Revoke**\` button as seen in the following screenshot.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/PfYCSNlbIWLgdN9ALMkVI_image.png)


[title] Activate License (Online Method)
[path] License API/License Activation/Deactivation/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/activate_license",
  "name": "/api/v4/activate_license",
  "method": "POST",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "String",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "kind": "optional",
        "name": "license_key",
        "type": "string",
        "children": [],
        "description": "Required if product is key-based (see section below)"
      },
      {
        "kind": "optional",
        "name": "username",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "kind": "optional",
        "name": "password",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "kind": "optional",
        "name": "id_token",
        "type": "string",
        "children": [],
        "description": "Required if using SSO (see section below). This is the id_token received from the SSO if Implicit grant authorization method is being used."
      },
      {
        "kind": "optional",
        "name": "code",
        "type": "string",
        "children": [],
        "description": "Required if using SSO (see section below). This is the code received from the SSO if Authorization code grant method is being used."
      },
      {
        "kind": "optional",
        "name": "customer_account_code",
        "type": "string",
        "children": [],
        "description": "Required if using SSO (see section below). This is the customer_account_code to which SSO provider is configured. "
      },
      {
        "name": "redirect_uri",
        "kind": "optional",
        "type": "string",
        "description": "Required if using SSO with a non-default Redirect URI (see below)",
        "": "Required if using SSO with a non-default Redirect URI (see below)"
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "Number",
        "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "children": []
      },
      {
        "kind": "optional",
        "name": "is_vm",
        "type": "Boolean",
        "children": [],
        "description": "Set to true if request is sent from a Virtual Machine. If this value is true and prevent VM is set on the license, an error will be returned. If this value is set (true or false), it will be stored in license device data"
      },
      {
        "kind": "optional",
        "name": "vm_info",
        "type": "string",
        "children": [],
        "description": "A string describing the Virtual Machine environment which will be stored in license device data"
      },
      {
        "kind": "optional",
        "name": "os_ver",
        "type": "string",
        "children": [],
        "description": "Operating System description string which will be stored in license device data"
      },
      {
        "kind": "optional",
        "name": "hostname",
        "type": "string",
        "children": [],
        "description": "Hostname string which will be stored in license device data"
      },
      {
        "kind": "optional",
        "name": "os_hostname",
        "type": "string",
        "children": [],
        "description": "Legacy version of \"hostname\" parameter (see above)"
      },
      {
        "kind": "optional",
        "name": "ip",
        "type": "string",
        "children": [],
        "description": "Client IP address string which will be stored in license device data"
      },
      {
        "kind": "optional",
        "name": "ip_local",
        "type": "string",
        "children": [],
        "description": "Legacy version of \"ip\" parameter (see above)"
      },
      {
        "kind": "optional",
        "name": "app_ver",
        "type": "string",
        "children": [],
        "description": "Application version string which will be stored in license device data"
      },
      {
        "kind": "optional",
        "name": "sdk_ver",
        "type": "string",
        "children": [],
        "description": "SDK version string which will be stored in license device data"
      },
      {
        "kind": "optional",
        "name": "mac_address",
        "type": "string",
        "children": [],
        "description": "Client MAC address which will be stored in license device data"
      },
      {
        "name": "variables",
        "kind": "optional",
        "type": "Object",
        "description": "Stores device variables. Variables are sent as a JSON object where the key is the variable name, and the value is the value of the variable",
        "children": [],
        "schema": []
      }
    ],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "es8g1cuKJMbNPiIVt9VoF",
        "code": "{\n    \"license_signature\": \"{license_signature_here}\",\n    \"validity_period\": null,\n    \"product_features\": [\n        {\n      \t\t\"name\": \"feature 3\",\n            \"code\": \"F3\",\n            \"feature_type\": \"activation\",\n            \"expiry_date\": \"2022-02-25\"\n        },\n        {\n            \"name\": \"feature 4\",\n            \"code\": \"F4\",\n            \"feature_type\": \"consumption\",\n            \"max_consumption\": 10,\n            \"total_consumptions\": 0,\n          \t\"expiry_date\": null\n        }\n    ],\n    \"license_type\": \"perpetual\",\n    \"license_key\": \"1111-2222-3333-4444\",\n    \"is_trial\": false,\n    \"maintenance_period\": null,\n    \"custom_fields\": [\n        {\n            \"name\": \"Field1\",\n            \"data_type\": null,\n            \"value\": \"default\"\n        }\n    ],\n    \"max_activations\": 1,\n    \"times_activated\": 1,\n    \"customer\": {\n        \"email\": \"test@example.com\",\n        \"company_name\": \"\",\n        \"reference\": \"\",\n        \"phone\": \"\",\n        \"first_name\": \"\",\n        \"last_name\": \"\",\n        \"customer_account\": {\n            \"id\": 20,\n            \"name\": \"LicenseSpring Inc.\",\n            \"code\": \"licensespring_inc.\"\n        }\n    },\n    \"allow_overages\": false,\n    \"max_overages\": 0,\n    \"prevent_vm\": false,\n    \"is_floating_cloud\": false,\n    \"is_floating\": false,\n    \"floating_timeout\": 120,\n    \"transfer_count\": 417,\n    \"max_transfers\": 0,\n    \"start_date\": null,\n    \"product_details\": {\n        \"product_id\": 1586066454418173,\n        \"product_name\": \"Acme App\",\n        \"short_code\": \"XY\",\n        \"authorization_method\": \"license-key\"\n    },\n    \"can_borrow\": false,\n    \"max_borrow_time\": 0,\n    \"device_id\": 1642501399344530,\n    \"id\": 1620711133620270\n}",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "7eyIlKSv2QgJcowEsDZ-2",
        "code": "{\n    \"unknown_product\": \"Provided product was not found\",\n    \"license_not_found\": \"License with the provided license user not found\",\n    \"license_not_enabled\": \"The license is not enabled\",\n    \"vm_not_allowed\": \"Virtual machine not allowed\",\n    \"offline_floating_cloud_not_supported\": \" Floating cloud licenses cannot be activated offline.\",\n    \"license_start_date_error\": \"This license cannot be activated before start date: {date}\",\n    \"blacklisted\": \"This device is blacklisted\",\n    \"license_activated_max_times\": \"This license  has already been activated the maximum number of times\",\n    \"license_user_activated_max_times\": \"License user has activated this license max times\",\n    \"license_expired\": \"License validity period has expired.\",\n    \"license_transferred_max_times\": \"This license has already been transferred the maximum number of times\",\n    \"license_device_exists\": \"A device matching this hardware_id is already created on the license\"\n}",
        "language": "400",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "es8g1cuKJMbNPiIVt9VoF"
  },
  "examples": {
    "languages": [
      {
        "id": "CZWU6THnRQg1GUpNIePNI",
        "code": "curl --location --request POST '/api/v4/activate_license' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string' \\\n--data-raw '{\"hardware_id\":\"String\",\"product\":\"string\",\"license_key\":\"string\",\"username\":\"string\",\"password\":\"string\",\"id_token\":\"string\",\"code\":\"string\",\"customer_account_code\":\"string\",\"is_vm\":\"Boolean\",\"vm_info\":\"string\",\"os_ver\":\"string\",\"hostname\":\"string\",\"os_hostname\":\"string\",\"ip\":\"string\",\"ip_local\":\"string\",\"app_ver\":\"string\",\"sdk_ver\":\"string\",\"mac_address\":\"string\"}'",
        "language": "curl",
        "customLabel": ""
      },
      {
        "id": "iijLVaTpMZXSOO-e7JyMJ",
        "code": "var request = require('request');\nvar options = {\n   'method': 'POST',\n   'url': '/api/v4/activate_license',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   },\n   body: '{\"hardware_id\":\"String\",\"product\":\"string\",\"license_key\":\"string\",\"username\":\"string\",\"password\":\"string\",\"id_token\":\"string\",\"code\":\"string\",\"customer_account_code\":\"string\",\"is_vm\":\"Boolean\",\"vm_info\":\"string\",\"os_ver\":\"string\",\"hostname\":\"string\",\"os_hostname\":\"string\",\"ip\":\"string\",\"ip_local\":\"string\",\"app_ver\":\"string\",\"sdk_ver\":\"string\",\"mac_address\":\"string\"}'\n\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "language": "nodejs",
        "customLabel": ""
      },
      {
        "id": "xvxt1tUwOev1j0hw305jg",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar raw = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"password\\\":\\\"string\\\",\\\"id_token\\\":\\\"string\\\",\\\"code\\\":\\\"string\\\",\\\"customer_account_code\\\":\\\"string\\\",\\\"is_vm\\\":\\\"Boolean\\\",\\\"vm_info\\\":\\\"string\\\",\\\"os_ver\\\":\\\"string\\\",\\\"hostname\\\":\\\"string\\\",\\\"os_hostname\\\":\\\"string\\\",\\\"ip\\\":\\\"string\\\",\\\"ip_local\\\":\\\"string\\\",\\\"app_ver\\\":\\\"string\\\",\\\"sdk_ver\\\":\\\"string\\\",\\\"mac_address\\\":\\\"string\\\"}\";\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/activate_license\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "language": "javascript",
        "customLabel": ""
      },
      {
        "id": "q-2i3bLnzmCC8J0i7r7gV",
        "code": "import requests\n\nurl = \"/api/v4/activate_license\"\n\npayload = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"password\\\":\\\"string\\\",\\\"id_token\\\":\\\"string\\\",\\\"code\\\":\\\"string\\\",\\\"customer_account_code\\\":\\\"string\\\",\\\"is_vm\\\":\\\"Boolean\\\",\\\"vm_info\\\":\\\"string\\\",\\\"os_ver\\\":\\\"string\\\",\\\"hostname\\\":\\\"string\\\",\\\"os_hostname\\\":\\\"string\\\",\\\"ip\\\":\\\"string\\\",\\\"ip_local\\\":\\\"string\\\",\\\"app_ver\\\":\\\"string\\\",\\\"sdk_ver\\\":\\\"string\\\",\\\"mac_address\\\":\\\"string\\\"}\"\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "language": "python",
        "customLabel": ""
      },
      {
        "id": "08XAeN4jaCQJ--JrN1Oqd",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/activate_license\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\nrequest.body = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"password\\\":\\\"string\\\",\\\"id_token\\\":\\\"string\\\",\\\"code\\\":\\\"string\\\",\\\"customer_account_code\\\":\\\"string\\\",\\\"is_vm\\\":\\\"Boolean\\\",\\\"vm_info\\\":\\\"string\\\",\\\"os_ver\\\":\\\"string\\\",\\\"hostname\\\":\\\"string\\\",\\\"os_hostname\\\":\\\"string\\\",\\\"ip\\\":\\\"string\\\",\\\"ip_local\\\":\\\"string\\\",\\\"app_ver\\\":\\\"string\\\",\\\"sdk_ver\\\":\\\"string\\\",\\\"mac_address\\\":\\\"string\\\"}\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "language": "ruby",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "CZWU6THnRQg1GUpNIePNI"
  },
  "description": "Activate a license for a product\n",
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "apiv4activatelicense",
  "legacyHash": "KnONhd9BIvTJtsZQ-J6_J"
}
```
:::

## Schema

### Request Body

:::CodeblockTabs
```typescript
type LicenseActivationRequestBody = ({

  // for key-based licenses:
  license_key: string

} | {

  // for user-based licenses, using username & password authentication:
  username: string
  password: string

} | {

  // for user-based licenses, using single sign-on Implicit grant authentication:
  id_token: string
  customer_account_code: string

} | {

  // for user-based licenses, using single sign-on Authorization code grant authentication:
  code: string
  customer_account_code: string

}) & {

  // required properties:
  hardware_id: string
  product: string

  // optional properties:
  bundle_code?: string | undefined
  license_id?: number | undefined
  is_vm?: boolean | undefined
  vm_info?: string | undefined
  os_ver?: string | undefined
  hostname?: string | undefined
  os_hostname?: string | undefined
  ip?: string | undefined
  ip_local?: string | undefined
  app_ver?: string | undefined
  sdk_ver?: string | undefined
  mac_address?: string | undefined
  variables?: { [key: string]: string } | undefined
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "allOf": [
    {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "license_key": { "type": "string" }
          },
          "required": ["license_key"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "username": { "type": "string" },
            "password": { "type": "string" }
          },
          "required": ["username", "password"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "id_token": { "type": "string" },
            "customer_account_code": { "type": "string" }
          },
          "required": ["id_token", "customer_account_code"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "code": { "type": "string" },
            "customer_account_code": { "type": "string" }
          },
          "required": ["code", "customer_account_code"],
          "additionalProperties": false
        }
      ]
    },
    {
      "type": "object",
      "properties": {
        "hardware_id": { "type": "string" },
        "product": { "type": "string" },
        "bundle_code": { "type": "string" },
        "license_id": { "type": "number" },
        "is_vm": { "type": "boolean" },
        "vm_info": { "type": "string" },
        "os_ver": { "type": "string" },
        "hostname": { "type": "string" },
        "os_hostname": { "type": "string" },
        "ip": { "type": "string" },
        "ip_local": { "type": "string" },
        "app_ver": { "type": "string" },
        "sdk_ver": { "type": "string" },
        "mac_address": { "type": "string" },
        "variables": {
          "type": ["object", "null"],
          "additionalProperties": { "type": "string" }
        }
      },
      "required": ["hardware_id", "product"],
      "additionalProperties": false
    }
  ]
}
```
:::

### Response Body

:::CodeblockTabs
```typescript
type LicenseActivationResponseBody = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  borrowed_until: string | null,
  can_borrow: boolean,
  device_id: number,
  enable_maintenance_period: boolean
  floating_timeout: number,
  grace_period: number,
  is_air_gapped: boolean,
  is_borrowed: boolean,
  is_expired: boolean,
  is_floating_cloud: boolean,
  is_floating: boolean,
  is_hardware_key_auth: boolean,
  license_active: boolean,
  license_enabled: boolean,
  license_signature: string,
  license_type: string,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users: number,
  max_overages: number,
  max_transfers: number,
  order_store_id: string,
  prevent_vm: boolean,
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null, // string is in DateISO8601UTC format
  company: { id: number },
  installation_file_id: number | null,
  installation_file: null | {
    id: number,
    channel: string,
    environment: string,
    eula_link: string,
    hash_md5: string,
    installation_file: string,
    release_date: string | null,
    release_notes_link: string,
    requires_version: string | null,
    size: string | null,
    version: string,
  },
  
  product_features: ({
    id: number,
    code: string,
    name: string,
    expiry_date: string,
    metadata: JSON,
    feature_type: 'activation' | 'consumption',
    is_floating: boolean,
    is_floating_cloud: boolean,

    // the following properties are only present if is_floating=true or is_floating_cloud=true
    floating_users: number,
    floating_timeout: number,

    // the following properties are only present if feature_type=consumption
    max_consumption: number,
    allow_unlimited_consumptions: boolean,
    total_consumptions: number,
    allow_overages: number,
    max_overages: number,
    reset_consumption: boolean,
    consumption_period: 'daily' | 'weekly' | 'monthly' | 'annualy' | null,
    can_borrow: boolean,
    max_borrow_time: number,
  })[],
  
  custom_fields: ({
    name: string,
    data_type: 'numer' | 'text' | 'date/time',
    value: string,
  })[],
  
  customer: {
    email: string,
    company_name: string,
    reference: string,
    phone: string,
    first_name: string,
    last_name: string,
    city: string,
    postcode: string,
    state: string,
    country: string,
    address: string,
    customer_account: string | null,
    metadata: JSON,
  },
  
  product_details: {
    product_id: number,
    product_name: string,
    short_code: string,
    authorization_method: 'license-key' | 'user',
    metadata: JSON,
  },
  
  metadata: JSON,
  
  // the following property is only present if is_trial=true
  trial_days: number,
  
  // the following properties is only present if is_floating=true or is_floating_cloud=true
  floating_in_use_devices: number,
  floating_users: number,
  
  // the following properties are only present if license_type='consumption'
  max_consumptions: number,
  total_consumptions: number,
  allow_unlimited_consumptions: boolean,
  reset_consumption: boolean,
  consumption_period: string | null, // string is in DateISO8601UTC format
  
} & ({

  // for key-based licenses:
  license_key: string,

} | {

  // for user-based licenses:
  user: {
    id: number,
    email: string,
    first_name: string,
    last_name: string,
    phone_number: string,
    is_initial_password: boolean,
    max_activations: number,
    allow_unlimited_activations: boolean,
    total_activations: number
  }
});

```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "allOf": [
    {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "license_key": { "type": "string" }
          },
          "required": ["license_key"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "user": {
              "type": "object",
              "properties": {
                "id": { "type": "number" },
                "email": { "type": "string" },
                "first_name": { "type": "string" },
                "last_name": { "type": "string" },
                "phone_number": { "type": "string" },
                "is_initial_password": { "type": "boolean" },
                "max_activations": { "type": "number" },
                "allow_unlimited_activations": { "type": "boolean" },
                "total_activations": { "type": "number" }
              },
              "required": ["id", "email", "first_name", "last_name", "phone_number", "is_initial_password", "max_activations", "allow_unlimited_activations", "total_activations"],
              "additionalProperties": false
            }
          },
          "required": ["user"],
          "additionalProperties": false
        }
      ]
    },
    {
      "type": "object",
      "properties": {
        "id": { "type": "number" },
        "allow_grace_period": { "type": "boolean" },
        "allow_overages": { "type": "boolean" },
        "allow_unlimited_activations": { "type": "boolean" },
        "borrowed_until": { "type": ["string", "null"] },
        "can_borrow": { "type": "boolean" },
        "device_id": { "type": "number" },
        "enable_maintenance_period": { "type": "boolean" },
        "floating_timeout": { "type": "number" },
        "grace_period": { "type": "number" },
        "is_air_gapped": { "type": "boolean" },
        "is_borrowed": { "type": "boolean" },
        "is_expired": { "type": "boolean" },
        "is_floating_cloud": { "type": "boolean" },
        "is_floating": { "type": "boolean" },
        "is_hardware_key_auth": { "type": "boolean" },
        "license_active": { "type": "boolean" },
        "license_enabled": { "type": "boolean" },
        "license_signature": { "type": "string" },
        "license_type": { "type": "string" },
        "maintenance_period": { "type": ["string", "null"] },
        "max_activations": { "type": "number" },
        "max_borrow_time": { "type": "number" },
        "max_license_users": { "type": "number" },
        "max_overages": { "type": "number" },
        "max_transfers": { "type": "number" },
        "order_store_id": { "type": "string" },
        "prevent_vm": { "type": "boolean" },
        "start_date": { "type": ["string", "null"] },
        "times_activated": { "type": "number" },
        "transfer_count": { "type": "number" },
        "validity_period": { "type": ["string", "null"] },
        "installation_file_id": { "type": ["number","null"] },
        "installation_file": {
            "type": "object",
            "properties": {
                "version": { "type": ["string", "null"] },
                "environment": { "type": "string" },
                "hash_md5": { "type": ["string", "null"] },
                "eula_link": { "type": ["string", "null"] },
                "release_notes_link": { "type": ["string", "null"] },
                "size": { "type": ["string", "null"] },
                "requires_version": { "type": ["string", "null"] },
                "channel": { "type": ["string", "null"] },
                "installation_file": { "type": ["string", "null"] },
                "release_date": { "type": ["string", "null"] }
            }
        },
        "company": { "type": "object", "properties": {"id": { "type": "number" } } },
        "product_features": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": { "type": "number" },
              "code": { "type": "string" },
              "name": { "type": "string" },
              "expiry_date": { "type": "string" },
              "metadata": {},
              "feature_type": { "type": "string", "enum": ["activation", "consumption"] },
              "is_floating": { "type": "boolean" },
              "is_floating_cloud": { "type": "boolean" },
              "floating_users": { "type": "number" },
              "floating_timeout": { "type": "number" },
              "max_consumption": { "type": "number" },
              "allow_unlimited_consumptions": { "type": "boolean" },
              "total_consumptions": { "type": "number" },
              "allow_overages": { "type": "number" },
              "max_overages": { "type": "number" },
              "reset_consumption": { "type": "boolean" },
              "max_borrow_time": { "type": "number" },
              "can_borrow": { "type": "boolean" },
              "consumption_period": {
                "type": ["string", "null"],
                "enum": ["daily", "weekly", "monthly", "annualy", null]
              }
            },
            "required": ["id", "code", "name", "expiry_date", "metadata", "feature_type", "is_floating", "is_floating_cloud"]
          }
        },
        "custom_fields": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "name": { "type": "string" },
              "data_type": { "type": "string", "enum": ["numer", "text", "date/time"] },
              "value": { "type": "string" }
            },
            "required": ["name", "data_type", "value"]
          }
        },
        "customer": {
          "type": "object",
          "properties": {
            "email": { "type": "string" },
            "company_name": { "type": "string" },
            "reference": { "type": "string" },
            "phone": { "type": "string" },
            "first_name": { "type": "string" },
            "last_name": { "type": "string" },
            "city": { "type": "string" },
            "postcode": { "type": "string" },
            "state": { "type": "string" },
            "country": { "type": "string" },
            "address": { "type": "string" },
            "customer_account": { "type": ["string", "null"] },
            "metadata": {}
          },
          "required": ["email", "company_name", "reference", "phone", "first_name", "last_name", "city", "postcode", "state", "country", "address", "metadata"]
        },
        "product_details": {
          "type": "object",
          "properties": {
            "product_id": { "type": "number" },
            "product_name": { "type": "string" },
            "short_code": { "type": "string" },
            "authorization_method": { "type": "string", "enum": ["license-key", "user"] },
            "metadata": {}
          },
          "required": ["product_id", "product_name", "short_code", "authorization_method", "metadata"]
        },
        "metadata": {},
        "trial_days": { "type": "number" },
        "floating_in_use_devices": { "type": "number" },
        "floating_users": { "type": "number" },
        "max_consumptions": { "type": "number" },
        "total_consumptions": { "type": "number" },
        "allow_unlimited_consumptions": { "type": "boolean" },
        "reset_consumption": { "type": "boolean" },
        "consumption_period": { "type": ["string", "null"] }
      },
      "required": [
        "id",
        "allow_grace_period",
        "allow_overages",
        "allow_unlimited_activations",
        "can_borrow",
        "channel",
        "device_id",
        "enable_maintenance_period",
        "environment",
        "eula_link",
        "floating_timeout",
        "grace_period",
        "hash_md5",
        "installation_file",
        "is_air_gapped",
        "is_borrowed",
        "is_expired",
        "is_floating_cloud",
        "is_floating",
        "is_hardware_key_auth",
        "license_active",
        "license_enabled",
        "license_signature",
        "license_type",
        "max_activations",
        "max_borrow_time",
        "max_license_users",
        "max_overages",
        "max_transfers",
        "order_store_id",
        "prevent_vm",
        "release_date",
        "release_notes_link",
        "requires_version",
        "size",
        "times_activated",
        "transfer_count",
        "version",
        "product_features",
        "custom_fields",
        "customer",
        "product_details",
        "metadata"
      ],
      "additionalProperties": false
    }
  ]
}
```
:::

### Response Signature

The response objects contains a `license_signature` value which the client app can use to verify the authenticty of the response (see the [**Response Signature**](docId\:ouciGcAGCAIKAdWCbx9Wk) article for instructions on how to verify this signature).

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

### Key-based product licenses

Each license assigned to the product requires the client to provide a license key in order to activate, check or deactivate the license (property `license_key` in the request body).

The license response object will contain the `license_key` property, and the property `product_details.authorization_method` will be the string `license_key`.

### User-based product licenses

Each license assigned to the product has a corresponding "license user" instead of a license key. There are multiple ways a user-based product license can be accessed when making a request:

- By providing the values for `username` and `password` for the license user
- By providing the values for `id_token` and `customer_account_code` if using single sign-on authentication using Implicit grant
- By providing the values for `code` and `customer_account_code` if using single sign-on authentication using Authorization code grant
-

In the license response object, `product_details.authorization_method` will have the string value `user` and the response object will contain the `user` object with information on the license user.&#x20;

## License Types

The `license_type` property defines one of the 4 types of licenses based on their duration and how the license is used:

- Perpetual: `perpetual`
- Time-limited: `time-limited`
- Subscription: `subscription`
- Consumption: `consumption`

For more information see: [**License Types**](docId\:xHxttCVj7gs6qeAqu7Cua)&#x20;

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**license\_not\_found** (400): License with the provided license user not found
:::

:::BlockQuote
**license\_not\_enabled** (400): The license is not enabled
:::

:::BlockQuote
**vm\_not\_allowed** (400): Virtual machine not allowed
:::

:::BlockQuote
**offline\_floating\_cloud\_not\_supported** (400): Floating cloud licenses cannot be activated offline
:::

:::BlockQuote
**license\_start\_date\_error&#x20;**(400): This license cannot be activated before start date: \{date}
:::

:::BlockQuote
**blacklisted** (400): This device is blacklisted
:::

:::BlockQuote
**license\_activated\_max\_times&#x20;**(400): This license key has already been activated the maximum number of times
:::

:::BlockQuote
**license\_user\_activated\_max\_times** (400): License user has activated this license max times
:::

:::BlockQuote
**license\_expired** (400): License validity period has expired
:::

:::BlockQuote
**license\_transferred\_max\_times&#x20;**(400): This license has already been transferred the maximum number of times
:::

:::BlockQuote
**license\_device\_exists&#x20;**(409): A device matching this hardware\_id is already created on the license.
:::

:::BlockQuote
**product\_version\_not\_supported&#x20;**(400): License product version does not support the app\_ver sent in the request
:::

## Examples

### User-Based License Activation

```curl
curl --location --request POST 'https://api.licensespring.com/api/v4/activate_license/' \
--header 'Date: Mon, 10 May 2021 13:14:18 GMT' \
--header 'Authorization: algorithm="hmac-sha256",headers="date",signature="{generated_signature}",apikey="{your_api_key}"' \
--header 'Content-Type: application/json' \
--data-raw '{
    "username": "test@example.com",
    "password": "some_password123",
    "hardware_id": "some-unique-id",
    "product": "XY"
}'
```

### Single-Sign-On License Activation

:::hint{type="info"}
Short instructions and link to detailed section about using Single Sign On directly via License Api can be find [**Single Sign-On URL**](docId\:QbJwnphsDcS0L25UW6PTq)&#x20;
:::

```curl
curl --location --request POST 'https://api.licensespring.com/api/v4/activate_license/' \
--header 'Date: Mon, 10 May 2021 13:14:18 GMT' \
--header 'Authorization: algorithm="hmac-sha256",headers="date",signature="{generated_signature}",apikey="{your_api_key}"' \
--header 'Content-Type: application/json' \
--data-raw '{
    "id_token": "{id_token_here}",
  	"code": "{code_here}",
    "customer_account_code": "acme_inc",
    "hardware_id": "some-unique-id",
    "product": "XY"
}'
```

:::hint{type="warning"}
Use either id\_token or code, not both at the same time.
:::

:::hint{type="warning"}
If you're using SSO with multiple redirect\_uri values enabled, you have to provide the `redirect_uri` in this request payload if it's the non-default uri (i.e. not the first one in the uri list)
:::

## Device Variables

The optional `variables` property lets you set device variables during activation. For more information on how device variables work, see [**Device Variables**](docId\:r2cnEKm7RUFf-U0JKM0Lw)


[title] Activate Bundle (Offline Method)
[path] License API/License Activation/Deactivation/

:::hint{type="info"}
Currently we support trial, perpetual and consumption license types for offline activation purposes
:::

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/activate_bundle_offline",
  "name": "/api/v4/activate_bundle_offline",
  "method": "POST",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [
      {
        "name": "base64-encoded JSON object",
        "kind": "required",
        "type": "Object",
        "description": "The request body is a base64-encoded stringified JSON object containing the properties below. See the \"Finalized payload\" section for examples on how to generate this payload",
        "children": [
          {
            "name": "api_key OR client_id",
            "kind": "required",
            "type": "string",
            "description": "Authorization parameter used for the request, either `api_key` if using API key-based authorization, or `client_id` if using SSO authorization"
          },
          {
            "name": "date",
            "kind": "required",
            "type": "string",
            "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
          },
          {
            "name": "request_id",
            "kind": "required",
            "type": "string",
            "description": "Custom unique ID used to identify the request"
          },
          {
            "name": "request",
            "kind": "required",
            "type": "string",
            "description": "Determines the type of request: \"activation\" or \"deactivation\""
          },
          {
            "name": "signature",
            "kind": "required",
            "type": "string",
            "description": "Calculated request signature (see section below)"
          },
          {
            "name": "product",
            "kind": "required",
            "type": "string",
            "description": "Product short code"
          },
          {
            "name": "hardware_id",
            "kind": "required",
            "type": "string",
            "description": "Unique hardware ID generated for the client device"
          },
          {
            "name": "license_key",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is key-based (see section below)"
          },
          {
            "name": "username",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is user based (see section below)"
          },
          {
            "name": "password",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is user based (see section below)"
          },
          {
            "name": "license_id",
            "kind": "optional",
            "type": "Number",
            "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user"
          },
          {
            "name": "os_ver",
            "kind": "optional",
            "type": "string",
            "description": "Operating System description string which will be stored in license device data"
          },
          {
            "name": "hostname",
            "kind": "optional",
            "type": "string",
            "description": "Hostname string which will be stored in license device data"
          },
          {
            "name": "os_hostname",
            "kind": "optional",
            "type": "string",
            "description": "Legacy version of \"hostname\" parameter (see above)"
          },
          {
            "name": "ip",
            "kind": "optional",
            "type": "string",
            "description": "Client IP address string which will be stored in license device data"
          },
          {
            "name": "ip_local",
            "kind": "optional",
            "type": "string",
            "description": "Legacy version of \"ip\" parameter (see above)"
          },
          {
            "name": "app_ver",
            "kind": "optional",
            "type": "string",
            "description": "Application version string which will be stored in license device data"
          },
          {
            "name": "sdk_ver",
            "kind": "optional",
            "type": "string",
            "description": "SDK version string which will be stored in license device data"
          },
          {
            "name": "mac_address",
            "kind": "optional",
            "type": "string",
            "description": "Client MAC address which will be stored in license device data"
          },
          {
            "name": "variables",
            "kind": "optional",
            "type": "Object",
            "description": "Stores device variables. Variables are sent as a JSON object where the key is the variable name, and the value is the value of the variable"
          }
        ],
        "schema": [
          {
            "name": "api_key OR client_id",
            "kind": "required",
            "type": "string",
            "description": "Authorization parameter used for the request, either `api_key` if using API key-based authorization, or `client_id` if using SSO authorization"
          },
          {
            "name": "date",
            "kind": "required",
            "type": "string",
            "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
          },
          {
            "name": "request_id",
            "kind": "required",
            "type": "string",
            "description": "Custom unique ID used to identify the request"
          },
          {
            "name": "request",
            "kind": "required",
            "type": "string",
            "description": "Determines the type of request: \"activation\" or \"deactivation\""
          },
          {
            "name": "signature",
            "kind": "required",
            "type": "string",
            "description": "Calculated request signature (see section below)"
          },
          {
            "name": "product",
            "kind": "required",
            "type": "string",
            "description": "Product short code"
          },
          {
            "name": "hardware_id",
            "kind": "required",
            "type": "string",
            "description": "Unique hardware ID generated for the client device"
          },
          {
            "name": "license_key",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is key-based (see section below)"
          },
          {
            "name": "username",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is user based (see section below)"
          },
          {
            "name": "password",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is user based (see section below)"
          },
          {
            "name": "license_id",
            "kind": "optional",
            "type": "Number",
            "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user"
          },
          {
            "name": "os_ver",
            "kind": "optional",
            "type": "string",
            "description": "Operating System description string which will be stored in license device data"
          },
          {
            "name": "hostname",
            "kind": "optional",
            "type": "string",
            "description": "Hostname string which will be stored in license device data"
          },
          {
            "name": "os_hostname",
            "kind": "optional",
            "type": "string",
            "description": "Legacy version of \"hostname\" parameter (see above)"
          },
          {
            "name": "ip",
            "kind": "optional",
            "type": "string",
            "description": "Client IP address string which will be stored in license device data"
          },
          {
            "name": "ip_local",
            "kind": "optional",
            "type": "string",
            "description": "Legacy version of \"ip\" parameter (see above)"
          },
          {
            "name": "app_ver",
            "kind": "optional",
            "type": "string",
            "description": "Application version string which will be stored in license device data"
          },
          {
            "name": "sdk_ver",
            "kind": "optional",
            "type": "string",
            "description": "SDK version string which will be stored in license device data"
          },
          {
            "name": "mac_address",
            "kind": "optional",
            "type": "string",
            "description": "Client MAC address which will be stored in license device data"
          },
          {
            "name": "variables",
            "kind": "optional",
            "type": "Object",
            "description": "Stores device variables. Variables are sent as a JSON object where the key is the variable name, and the value is the value of the variable"
          }
        ]
      }
    ],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "es8g1cuKJMbNPiIVt9VoF",
        "code": "",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "7eyIlKSv2QgJcowEsDZ-2",
        "code": "",
        "language": "400",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "es8g1cuKJMbNPiIVt9VoF"
  },
  "examples": {
    "languages": [
      {
        "id": "MVswmprxv53Y8L_yhrmmd",
        "language": "curl",
        "code": "curl --location --request POST '/api/v4/activate_bundle_offline' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string' \\\n--data-raw '_BASE64_PAYLOAD_HERE_'",
        "customLabel": ""
      },
      {
        "id": "ZCTQO7_LVyOjAVX7pP4kO",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'POST',\n   'url': '/api/v4/activate_bundle_offline',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   },\n   body: Buffer.from(JSON.stringify(offline_payload)).toString('base64')\n};\n\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "LI5XFmSVTa4QEJC9tahg2",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: btoa(JSON.stringify(offline_payload)),\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/activate_bundle_offline\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "cmQNdWH3b3clWrX7G_IxJ",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/activate_bundle_offline\"\n\npayload = \"{\\\"Payload\\\":\\\"Object\\\"}\"\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "i6V2Wf-nI00sMv9ahE5rB",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/activate_bundle_offline\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\nrequest.body = \"{\\\"Payload\\\":\\\"Object\\\"}\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "i6V2Wf-nI00sMv9ahE5rB"
  },
  "description": "Activates all licenses inside of a bundle using the offline activation method. Returns the list of activated licenses in response\n",
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "apiv4activatebundleoffline",
  "legacyHash": "QO5GDP0RzYbnGkCFOCK7Y"
}
```
:::

## Schema

### Request Body

The request body is a string representing a base64-encoded JSON object containing all the required activation data.

:::hint{type="danger"}
If using "multipart/form-data" for the request, the "file" form parameter is mandatory
:::

:::CodeblockTabs
```typescript
type LicenseOfflineActivationObject = ({

  // for key-based licenses:
  license_key: string

} | {

  // for user-based licenses:
  username: string
  password: string

}) & {

  // required properties:
  hardware_id: string
  product: string
  request_id: string
  signature: string
  date: string
  request: "activation"

} & ({
  api_key: string // for API key authorization
} | {
  client_id: string // for OAuth authorization
}) & {

  // optional properties:
  bundle_code?: string | undefined
  license_id?: number | undefined
  is_vm?: boolean | undefined
  vm_info?: string | undefined
  os_ver?: string | undefined
  hostname?: string | undefined
  os_hostname?: string | undefined
  ip?: string | undefined
  ip_local?: string | undefined
  app_ver?: string | undefined
  sdk_ver?: string | undefined
  mac_address?: string | undefined
  variables?: { [key: string]: string } | undefined
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "allOf": [
    {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "license_key": { "type": "string" }
          },
          "required": ["license_key"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "username": { "type": "string" },
            "password": { "type": "string" }
          },
          "required": ["username", "password"],
          "additionalProperties": false
        }
      ]
    },
    {
      "type": "object",
      "properties": {
        "api_key": { "type": "string" },
        "client_id": { "type": "string" },
        "request": { "type": "string" },
        "request_id": { "type": "string" },
        "date": { "type": "string" },
        "signature": { "type": "string" },
        "hardware_id": { "type": "string" },
        "product": { "type": "string" },
        "bundle_code": { "type": "string" },
        "license_id": { "type": "number" },
        "is_vm": { "type": "boolean" },
        "vm_info": { "type": "string" },
        "os_ver": { "type": "string" },
        "hostname": { "type": "string" },
        "os_hostname": { "type": "string" },
        "ip": { "type": "string" },
        "ip_local": { "type": "string" },
        "app_ver": { "type": "string" },
        "sdk_ver": { "type": "string" },
        "mac_address": { "type": "string" },
        "variables": {
          "type": "object",
          "additionalProperties": { "type": "string" }
        }
      },
     "allOf": [
        { "anyOf": [{ "required": ["api_key"] }, { "required": ["client_id"] }] },
        { "anyOf": [{ "required": ["license_key"] }, { "required": ["username"] }] }
      ],
      "required": ["hardware_id", "product", "date", "signature"],
      "additionalProperties": false
    }
  ]
}
```
:::

### Signature

The `signature` value is constructed as follows:

1. The string `licenseSpring` plus a newline
2. The string `date`, plus the "date" value from the license payload object, plus a newline
3. Either the "license\_key" or "username" value from the request payload object (which ever is present on the license, see the License Authorization Method section below) plus a newline
4. The "hardware\_id" value from the request payload object plus a newline
5. The "api\_key" value from the request payload object

This complete string is then encrypted using **HMAC-SHA256** and the company **shared key** as the encryption key.

```javascript
import crypto from 'node:crypto';

const activationPayload = {
  // ...payload content...
};

// api_key or client_id depending on authorization type used:
const key = (activationPayload.api_key || activationPayload.client_id);

// if using API key authorization: the signing key is the Shared Key
// if using OAuth: the signing key is the Client Secret
const signingKey = '...';

const signingString =
  'licenseSpring\n' +
  'date: ' + activationPayload.date + '\n' +
  (activationPayload.license_key || activationPayload.username) + '\n' +
  activationPayload.hardware_id + '\n' +
  key;

  const signature = crypto
    .createHmac('sha256', signingKey)
    .update(signingString)
    .digest('base64');
```

### Finalized payload

This object is then stringified and encoded to base64, e.g.:

:::CodeblockTabs
JS Browser

```javascript
const activationPayload = {
  // ...payload content...
};
const requestBody = btoa(JSON.stringify(activationPayload));
```

nodeJS

```javascript
const activationPayload = {
  // ...payload content...
};
const requestBody = Buffer.from(JSON.stringify(activationPayload)).toString('base64');
```
:::

### Response Body

:::CodeblockTabs
```typescript
type BundleActivationResponseBody = {
  licenses: LicenseActivationResponse[],
  bundle_signature_v2: string,
};

type LicenseActivationResponse = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  borrowed_until: string | null,
  can_borrow: boolean,
  device_id: number,
  enable_maintenance_period: boolean
  floating_timeout: number,
  grace_period: number,
  is_air_gapped: boolean,
  is_borrowed: boolean,
  is_expired: boolean,
  is_floating_cloud: boolean,
  is_floating: boolean,
  is_hardware_key_auth: boolean,
  license_active: boolean,
  license_enabled: boolean,
  license_signature: string,
  license_signature_v2: string,
  offline_signature: string,
  license_type: string,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users: number,
  max_overages: number,
  max_transfers: number,
  order_store_id: string,
  prevent_vm: boolean,
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null, // string is in DateISO8601UTC format
  company: { id: number },
  installation_file_id: number | null,
  installation_file: null | {
    id: number,
    channel: string,
    environment: string,
    eula_link: string,
    hash_md5: string,
    installation_file: string,
    release_date: string | null,
    release_notes_link: string,
    requires_version: string | null,
    size: string | null,
    version: string,
  },
  
  product_features: ({
    id: number,
    code: string,
    name: string,
    expiry_date: string,
    metadata: JSON,
    feature_type: 'activation' | 'consumption',
    is_floating: boolean,
    is_floating_cloud: boolean,

    // the following properties are only present if is_floating=true or is_floating_cloud=true
    floating_users: number,
    floating_timeout: number,

    // the following properties are only present if feature_type=consumption
    max_consumption: number,
    allow_unlimited_consumptions: boolean,
    total_consumptions: number,
    allow_overages: number,
    max_overages: number,
    reset_consumption: boolean,
    consumption_period: 'daily' | 'weekly' | 'monthly' | 'annualy' | null,
    can_borrow: boolean,
    max_borrow_time: number,
  })[],
  
  custom_fields: ({
    name: string,
    data_type: 'numer' | 'text' | 'date/time',
    value: string,
  })[],
  
  customer: {
    email: string,
    company_name: string,
    reference: string,
    phone: string,
    first_name: string,
    last_name: string,
    city: string,
    postcode: string,
    state: string,
    country: string,
    address: string,
    customer_account: string | null,
    metadata: JSON,
  },
  
  product_details: {
    product_id: number,
    product_name: string,
    short_code: string,
    authorization_method: 'license-key' | 'user',
    metadata: JSON,
  },
  
  metadata: JSON,
  
  // the following property is only present if is_trial=true
  trial_days: number,
  
  // the following properties is only present if is_floating=true or is_floating_cloud=true
  floating_in_use_devices: number,
  floating_users: number,
  
  // the following properties are only present if license_type='consumption'
  max_consumptions: number,
  total_consumptions: number,
  allow_unlimited_consumptions: boolean,
  reset_consumption: boolean,
  consumption_period: string | null, // string is in DateISO8601UTC format
  
} & ({

  // for key-based licenses:
  license_key: string,

} | {

  // for user-based licenses:
  user: {
    id: number,
    email: string,
    first_name: string,
    last_name: string,
    phone_number: string,
    is_initial_password: boolean,
    max_activations: number,
    allow_unlimited_activations: boolean,
    total_activations: number
  }
});

```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "bundle_signature_v2": { "type": "string" },
    "licenses": {
      "type": "array",
      "items": {
        "type": "object",
        "allOf": [
          {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "license_key": { "type": "string" }
                },
                "required": ["license_key"],
                "additionalProperties": false
              },
              {
                "type": "object",
                "properties": {
                  "user": {
                    "type": "object",
                    "properties": {
                      "id": { "type": "number" },
                      "email": { "type": "string" },
                      "first_name": { "type": "string" },
                      "last_name": { "type": "string" },
                      "phone_number": { "type": "string" },
                      "is_initial_password": { "type": "boolean" },
                      "max_activations": { "type": "number" },
                      "allow_unlimited_activations": { "type": "boolean" },
                      "total_activations": { "type": "number" }
                    },
                    "required": [
                      "id",
                      "email",
                      "first_name",
                      "last_name",
                      "phone_number",
                      "is_initial_password",
                      "max_activations",
                      "allow_unlimited_activations",
                      "total_activations"
                    ],
                    "additionalProperties": false
                  }
                },
                "required": ["user"],
                "additionalProperties": false
              }
            ]
          },
          {
            "type": "object",
            "properties": {
              "id": { "type": "number" },
              "allow_grace_period": { "type": "boolean" },
              "allow_overages": { "type": "boolean" },
              "allow_unlimited_activations": { "type": "boolean" },
              "borrowed_until": { "type": ["string", "null"] },
              "can_borrow": { "type": "boolean" },
              "device_id": { "type": "number" },
              "enable_maintenance_period": { "type": "boolean" },
              "floating_timeout": { "type": "number" },
              "grace_period": { "type": "number" },
              "is_air_gapped": { "type": "boolean" },
              "is_borrowed": { "type": "boolean" },
              "is_expired": { "type": "boolean" },
              "is_floating_cloud": { "type": "boolean" },
              "is_floating": { "type": "boolean" },
              "is_hardware_key_auth": { "type": "boolean" },
              "license_active": { "type": "boolean" },
              "license_enabled": { "type": "boolean" },
              "license_signature": { "type": "string" },
              "license_signature_v2": { "type": "string" },
              "offline_signature": { "type": "string" },
              "license_type": { "type": "string" },
              "maintenance_period": { "type": ["string", "null"] },
              "max_activations": { "type": "number" },
              "max_borrow_time": { "type": "number" },
              "max_license_users": { "type": "number" },
              "max_overages": { "type": "number" },
              "max_transfers": { "type": "number" },
              "order_store_id": { "type": "string" },
              "prevent_vm": { "type": "boolean" },
              "start_date": { "type": ["string", "null"] },
              "times_activated": { "type": "number" },
              "transfer_count": { "type": "number" },
              "validity_period": { "type": ["string", "null"] },
              "installation_file_id": { "type": ["number","null"] },
              "installation_file": {
                  "type": "object",
                  "properties": {
                      "version": { "type": ["string", "null"] },
                      "environment": { "type": "string" },
                      "hash_md5": { "type": ["string", "null"] },
                      "eula_link": { "type": ["string", "null"] },
                      "release_notes_link": { "type": ["string", "null"] },
                      "size": { "type": ["string", "null"] },
                      "requires_version": { "type": ["string", "null"] },
                      "channel": { "type": ["string", "null"] },
                      "installation_file": { "type": ["string", "null"] },
                      "release_date": { "type": ["string", "null"] }
                  }
              },

              "company": {
                "type": "object",
                "properties": {
                  "id": { "type": "number" }
                }
              },

              "product_features": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": { "type": "number" },
                    "code": { "type": "string" },
                    "name": { "type": "string" },
                    "expiry_date": { "type": "string" },
                    "metadata": {},
                    "feature_type": { "type": "string", "enum": ["activation", "consumption"] },
                    "is_floating": { "type": "boolean" },
                    "is_floating_cloud": { "type": "boolean" },
                    "floating_users": { "type": "number" },
                    "floating_timeout": { "type": "number" },
                    "max_consumption": { "type": "number" },
                    "allow_unlimited_consumptions": { "type": "boolean" },
                    "total_consumptions": { "type": "number" },
                    "allow_overages": { "type": "number" },
                    "max_overages": { "type": "number" },
                    "reset_consumption": { "type": "boolean" },
                    "max_borrow_time": { "type": "number" },
                    "can_borrow": { "type": "boolean" },
                    "consumption_period": {
                      "type": ["string", "null"],
                      "enum": ["daily", "weekly", "monthly", "annualy", null]
                    }
                  },
                  "required": [
                    "id",
                    "code",
                    "name",
                    "expiry_date",
                    "metadata",
                    "feature_type",
                    "is_floating",
                    "is_floating_cloud"
                  ]
                }
              },

              "custom_fields": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": { "type": "string" },
                    "data_type": { "type": "string", "enum": ["numer", "text", "date/time"] },
                    "value": { "type": "string" }
                  },
                  "required": ["name", "data_type", "value"]
                }
              },

              "customer": {
                "type": "object",
                "properties": {
                  "email": { "type": "string" },
                  "company_name": { "type": "string" },
                  "reference": { "type": "string" },
                  "phone": { "type": "string" },
                  "first_name": { "type": "string" },
                  "last_name": { "type": "string" },
                  "city": { "type": "string" },
                  "postcode": { "type": "string" },
                  "state": { "type": "string" },
                  "country": { "type": "string" },
                  "address": { "type": "string" },
                  "customer_account": { "type": ["string", "null"] },
                  "metadata": {}
                },
                "required": [
                  "email",
                  "company_name",
                  "reference",
                  "phone",
                  "first_name",
                  "last_name",
                  "city",
                  "postcode",
                  "state",
                  "country",
                  "address",
                  "metadata"
                ]
              },

              "product_details": {
                "type": "object",
                "properties": {
                  "product_id": { "type": "number" },
                  "product_name": { "type": "string" },
                  "short_code": { "type": "string" },
                  "authorization_method": { "type": "string", "enum": ["license-key", "user"] },
                  "metadata": {}
                },
                "required": [
                  "product_id",
                  "product_name",
                  "short_code",
                  "authorization_method",
                  "metadata"
                ]
              },

              "metadata": {},
              "trial_days": { "type": "number" },
              "floating_in_use_devices": { "type": "number" },
              "floating_users": { "type": "number" },
              "max_consumptions": { "type": "number" },
              "total_consumptions": { "type": "number" },
              "allow_unlimited_consumptions": { "type": "boolean" },
              "reset_consumption": { "type": "boolean" },
              "consumption_period": { "type": ["string", "null"] }
            },
            "required": [
              "id",
              "allow_grace_period",
              "allow_overages",
              "allow_unlimited_activations",
              "can_borrow",
              "channel",
              "device_id",
              "enable_maintenance_period",
              "environment",
              "eula_link",
              "floating_timeout",
              "grace_period",
              "hash_md5",
              "installation_file",
              "is_air_gapped",
              "is_borrowed",
              "is_expired",
              "is_floating_cloud",
              "is_floating",
              "is_hardware_key_auth",
              "license_active",
              "license_enabled",
              "license_signature",
              "license_signature_v2",
              "offline_signature",
              "license_type",
              "max_activations",
              "max_borrow_time",
              "max_license_users",
              "max_overages",
              "max_transfers",
              "order_store_id",
              "prevent_vm",
              "release_date",
              "release_notes_link",
              "requires_version",
              "size",
              "times_activated",
              "transfer_count",
              "version",
              "product_features",
              "custom_fields",
              "customer",
              "product_details",
              "metadata"
            ],
            "additionalProperties": false
          }
        ]
      }
    }
  }
}

```
:::

### Response Signature

The response objects two digital signatures which the client app can use to verify the authenticty of the response:

1. `license_signature` is the HMAC-SHA256 signature explained in the [**Response Signature**](docId\:ouciGcAGCAIKAdWCbx9Wk) article
2. `offline_signature` is an additional HMAC-SHA256 signature specific to this endpoint. This value is constructed identically to the `signature` parameter in the request payload (see [**Activate Bundle (Offline Method)**](docId:0AWEA7jLUGzT14Z9_QSqi) above) using the `date` value received in the response

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

### Key-based product licenses

Each license assigned to the product requires the client to provide a license key in order to activate, check or deactivate the license (property `license_key` in the request body).

The license response object will contain the `license_key` property, and the property `product_details.authorization_method` will be the string `license_key`.

### User-based product licenses

Each license assigned to the product has a corresponding "license user" instead of a license key. Requires `username` and `password` to be provided.

In the license response object, `product_details.authorization_method` will have the string value `user` and the response object will contain the `user` object with information on the license user.&#x20;

## License Types

The `license_type` property defines one of the 4 types of licenses based on their duration and how the license is used:

- Perpetual: `perpetual`
- Time-limited: `time-limited`
- Subscription: `subscription`
- Consumption: `consumption`

For more information see: [**License Types**](docId\:xHxttCVj7gs6qeAqu7Cua)&#x20;

## Device variables

The optional `variables` parameter lets you set device variables during activation. For more information on how device variables work, see [**Device Variables**](docId\:r2cnEKm7RUFf-U0JKM0Lw)

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**missing\_headers** (400): some headers are missing
:::

- when missing authorization or date headers

:::BlockQuote
**missing\_parameters** (400): some parameters are missing in the request: different, parameters
:::

- when no request body at all or no file found in request body

:::BlockQuote
**authorization\_missing\_params** (400): some parameters are missing in authorization: different, parameters
:::

- when has request body but request body is not properly base 64 encoded
- when file is missing in request body
- when license\_key or hardware\_id body parameters are missing
- when data body parameter is missing
- when api\_key parameter is missing

:::BlockQuote
**product\_not\_bundle** (400): Specified product "\{CODE}" is not a bundle
:::

:::hint{type="info"}
If you want to use this api endpoint directly, instead of using SDK, which does most of heavy lifting for you, please contact us for additional instructions
:::

## Guide on using Offline Licenses

&#x20;If any aspect of the offline licensing model remains unclear or raises questions, we encourage you to explore our in-depth guide on [**link**](https://docs.licensespring.com/license-entitlements/activation-types/offline)

This resource offers a comprehensive explanation of the offline licensing process, how it operates, and ways to utilize its advantages for your specific software applications&#x20;


[title] Audit Log
[path] Vendor Platform/Settings/

The audit log is a useful table to keep track of all essential actions performed within an account, and who performed them.

## Where Audit Logs Can Be Seen

### In Aggregate

It can be found in aggregate by navigating to "Settings" > "Audit logs":



![Platform Audit Logs](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/2H5vBXaaseHWUjKQ0e25D_image.png "Platform Audit Logs")

### Per Individual Item

A table under each license, customer, order or product will contain logs for any action carried out on a particular item. They currently appear at the bottom of the following views:

- License detail view
- Order detail view
- Customer detail view
- Product detail view

![Individual Item Logs](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/IsJKCFiD90c8_vWl6fzci_image.png "Individual Item Logs")

## Actions Recorded Within the Audit Log

Here is a list of actions that are recorded when taken by a platform user:

### Platform Users

- `platform_user_added`
- `platform_user_updated`
- `platform_user_removed`

### Permissions Template for Platform Users

- `user_permission_template_created`
- `user_permission_template_updated`
- `user_permission_template_permissions_set`
- `user_permission_template_deleted`

### Email Notifications

- `notification_policy_created`
- `notification_policy_updated`
- `notification_policy_deleted`

### Products

- `product_created`
- `product_updated`
- `product_activated`
- `product_deactivated`
- `product_archived`
- `product_unarchived`
- `product_deleted`

### Customers

- `customer_created`
- `customer_updated`
- `customer_deleted`

### Orders

- `order_created`
- `order_updated`
- `order_manager_added`
- `order_manager_removed`
- `order_deleted`

### Licenses

- `license_created`
- `license_updated`
- `license_reset`
- `license_disabled`
- `license_enabled`
- `license_consumption_reset`
- `license_user_assigned`
- `license_user_unassigned`
- `license_features_updated`
- `license_deleted`
- `license_custom_field_created`
- `license_custom_field_updated`
- `license_custom_field_deleted`

### Devices

- `device_reset`
- `device_blacklisted`
- `device_borrowed`
- `device_borrow_released`

## Data Retention Period

The audit log is currently indefinite.

## Exporting the Audit Log

The audit log can be exported on a case-by-case basis.


[title] License Detail View
[path] Vendor Platform/Orders/

All licenses that have been issued within LicenseSpring will have their own license detail view.&#x20;

**To access the license editing page via the Orders tab, follow these steps:**

1. Go to the **Orders** tab.
2. Click on **Licenses**.
3. From the list, locate and select the license you want to edit.(You can click anywhere on the license row to open the edit license page.)

In this view, you can see all information associated with the license, ability to edit the license's entitlements including disabling or resetting a license, review the usage of the license in table format, along with analytics.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/oGH07XVkXXNrs6rtzO4rh_image.png "License Detail Page")

## Editing a License

:::hint{type="info"}
You cannot edit everything within a license. For example, you cannot edit a license type. You can however, add/remove features, change the expiry date (for time-limited licenses) or max activations
:::

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/4ELiubs3yiL1s0bHsBr0F_image.png)

Depending on the type of license that it is, you will be able make different types of changes.&#x20;

Some of the common changes for all licenses include:

- Changing the number of max activations allowed for that license
- Setting the number of device transfers allowed or preventing license transfers altogether
- Preventing virtual machines
- Changing the license start date
- Modifying whether or not the license is a floating license
- Modifying the maintenance period for that license

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/5UvjZLzGRaUfsmUG7hPmF_image.png)

## Reset a License

Resetting a license will reset license entitlements, including setting total activations to 0, deactivating license devices, resetting total consumptions, etc.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/VvKNMmMN6-VbBGzPlOPlD_image.png)

## Disable/Enable a License

Disabling a license will reject any attempts to activate, or perform a check on that license. Disabling a license will not change any of the entitlements to the license. The status of the license will be set to `Disabled`

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/XP9ret86YmeY6mNkmfPXe_image.png "Disable License Button")

&#x20;A disabled license can be re-enabled at a later date. The status will revert to whatever the status was if it was not disabled: `Inactive`/`Active`

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/_8q4lEpdxd4sZTQhHG61a_image.png "Enable License Button")

## Delete a License

Deleting a license will remove it from the LicenseSpring database. This is a destructive process, and cannot be reverted through the vendor platform.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/pi1BxtQbTNfpF6ntEcOgm_image.png "Delete License Button")

## Devices Associated With a License

Any device that has been activated a license will appear in this tab:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/5KO7tp--j8c6V6HhjoYS7_image.png "Devices Tab")

You can retrieve more information on the computer that activated the license by expanding the "details" arrow:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/VSeKkZb5DDHm3cKcZtOsV_image.png "Device Details Tab")

:::hint{type="info"}
Many of the fields are optional and do not need to be sent when activating a license. The only field that needs to be sent when activating a license is the Hardware ID.
:::

### Retrieve Current Device Variables

Devices can send key value pairs back to LicenseSpring. You can retrieve the most current values sent by clicking on the "Device Variables" button.



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/47_REWO-gOvZ8wfTB7atc_image.png "Retrieve Device Variables")

![Device Variables Display](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/BmNspJj_L5ghiPaqOPzbU_image.png "Device Variables Display")

### Reset Device

Resetting a device from the license details view will set the status of the device to `Inactive` and decrement the `Total activations` field by 1. The next time that device attempts any action using the License API, the server will return a 4XX error.



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/PjHwHcIb3pFc6NZr3Sylt_image.png "Device Actions Button")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Ok_A6VoTBeIHnFHcPYzIh_image.png)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Fit1q_uzoW1LEjeftkmO-_image.png)

### Blacklist/Whitelist Device:

Blacklisting a device will prevent that device from using it with this license. Blacklisted devices appear at the bottom of the view.

You can always unblock a device by whitelisting it.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/trFmjIWXAkjjA7euFasR7_image.png "Black List Button")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/sU07-4tkSOJtUv5Qc_Y6p_image.png "Whitelist Button")

### Get License Refresh File

When a license has been node-locked to a given device, a device-specific license file is created. which can be reach through the use of our SDKs to perform local license checks. This file is updated each time entitlements for the license change. You can download this file and send to the end user:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/tg9WSyrgxUAIU6QagJ8EN_image.png "Download License Refresh File Button")

## Edit License Custom Field

If the product has any custom fields defined, then the fields will always be available to all licenses issued for that product. You can override the value of the custom field for any given license.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/scgA_cQiqLkyU_CaNw9oO_image.png)

## Edit Product Features of the License

You can add/remove or modify features for any given license provided that those features have been defined for the license.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/vF3x9s8WQkyCiS_LFbX82_image.png "Edit Product License Features")

### Add/Remove a Feature

If a feature has not already been added to the license, you can select which feature to add.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/EvsFvwdWS_IF08gueVohq_image.png "Adding Product Feature")

:::hint{type="info"}
You can add an expiry date for an individual feature if you would like to limit the use of a module with time.
Additionally, you can define a valid\_duration ( same like for a time limited license, eq- 1m, 1y, etc. ) which will be recalculated as expiry\_date at the time of the first license activation.
:::

![Toggling Product Features](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/hMhoDS5KTInok_gvDZM6V_image.png "Toggling Product Features")

### Change Consumption Feature Allowances

You can modify the allowances for consumption features:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/eSinBvmRzENNqt7rjH9Vm_image.png "Editing Product Feature Button")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/zftrlG89PcNQN_83ZS7BK_image.png "Editing Product Feature View")

## License Usage Report

The license usage report includes tabular data on events that occurred on the license, such as license checks.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Em0n1HOW5aztw3eODDs2j_image.png "License Usage Report")

### List of license usage events

- License activated
- Offline license activated
- License check
- Consumption added
- Max consumptions reached
- Feature consumption added
- Max feature consumptions reached
- License created
- License deactivated
- Offline license deactivated
- Floating release
- Floating borrow
- Trial license created
- Get device variables
- Track device variables
- Get versions
- Get installation file

### Export License Usage Report in a CSV

You may download the CSV of the license usage report by specifying a date range, and clicking the download button.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/wFdToiTS23TmW7ytsRynQ_image.png "Export License Usage Report")

## Analytics

The [**Analytics**](docId\:oIeTvYvxQege2vY_XUle3) tab aggregates the license usage report data and plots it for better understanding.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/HOyob1frBs0bgwnhLdAi2_image.png "Anlalytics Tab")

### Analytics for All Licenses

Using the license detail view, you are able to see license-specific statistics, including:

- License checks
- Get device variables
- Track device variables

### Analytics for Consumption Licenses

Consumption licenses have unique statistics displayed, including:

- Daily consumptions
- Total consumptions
- Overages

Consumption events are also tracked, such as:

- Reset consumption
- Add consumption

:::hint{type="info"}
**Note:&#x20;**&#x4C;icense analytics also tracks license feature consumption
:::


[title] Add New Bundle
[path] Vendor Platform/Products/

A product bundle is a specific type of product which groups several products together so that they can be activated and used with a single license.

## General Process: Working With Product Bundles:

Generally, creating product bundles uses the following workflow:

- Step 1: Initialize a product bundle
- Step 2: Issue licenses for the product bundle.
- Step 3: Activate each product individually using the same license.

## Initialize a Product Bundle

Product bundles can be created on the Products page in the platform clicking on the button Add new bundle.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Xf8Pq3qzm7XK9HiM4Cm69_image.png "Adding New Product Bundle")

Enter the bundle name, code, authorization method select all the products which are going to be included in a bundle.

![Setting Bundle Values](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/NSZLjERf_0z-fFMdNcb24_image.png "Setting Bundle Values")

:::hint{type="info"}
The bundle code must be unique from other bundle and other product codes
:::

:::hint{type="info"}
You can only bundle products using the same authorization method
:::

:::hint{type="info"}
The Bundle code, authorization method and selected products cannot be edited after the bundle is created. You can edit their name, and delete or disable / re-enable them at a later date.
:::


[title] Basic Concepts
[path] Getting Started/

If you are new to LicenseSpring, or to software licensing in general, you might find it helpful to review the following concepts so that you can get up and running as quickly as possible.

## Product

![A Defined Product within the LicenseSpring Platform](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Qe8b716e3hfNIHezwDHh7_image.png "A Defined Product within the LicenseSpring Platform")

This is what you wish to add software licensing to. A product can be a web app, a desktop application, a plugin, a device/hardware or a microservice for example. A product can have many possible attributes, but here are a few that you should be aware of:

### Product Name

This is what you call your app. It can be anything, and is not particularly consequential for configuring your LicenseSpring account. The Product name can be edited at any time by a user of the vendor platform.

### Product Code

The product code is important as it is a required field for most of the License API calls.&#x20;

:::hint{type="warning"}
You cannot change a product code once you have defined a product in LicenseSpring, so choose it wisely!
:::

### Product Authorization

LicenseSpring supports key-based or user-based authorization:

- **Key-based licenses&#x20;**&#x75;se a license key to authorize a license with the License API. It is mostly used for Node-Locking licenses to a machine or device.
- **User-based licenses&#x20;**&#x72;equire that an email is assigned to a license. The user's email and password (or Single Sign On) is used as part of the Authorization Process

## Licenses

![An example license detail page](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/2mXZl1YIHlUbuj04S8c67_image.png "Screenshot of an example license detail page")

Licenses serve as a record of entitlements granted for a given product. These license entitlements can be issued, modified, transferred, revoked, and contain many configuration options. Here are a few of the main options to be aware of.

### License Types

There are 4 elementary types of licenses which can be issued using LicenseSpring:

- **Perpetual**: These licenses do not have expiry dates.
- **Time-Limited**: These licenses have a fixed end date. This end date can affect the license status.
- **Subscription**: The license status is determined by an external source of truth (like a recurring billing system such as Stripe). Subscriptions also have subscription periods recorded.
- **Consumption**: Allows for usage metering, such as counting the times a license application is run, or number of API requests.

### License Max Activations

Max activations is a field determining how many unique devices can be bound to a license.

### License Total Activations

Total activations is also a field that belongs to a license, and counts how many distinct devices have been bound to a given license.

:::hint{type="info"}
Total activations will always be less than or equal to max activations.
:::

### License Status

This is the state of a given license. There are many different states covered in different section in these docs. The main ones to be aware of:

- **Inactive**: The License has not been bound to any device but can currently be used. Specifically, the `total activations`  field is 0.
- **Active**: The License has been bound to at least 1 device, and can currently be used (is not disabled or expired)
- **Expired**: For licenses that can expire (eg: time limited licenses)
- **Disabled**: The Software vendor can set a license as disabled, which overrides other statuses. A Subscription license is disabled when the subscription is no longer active.

## Activation

The License Activation is the act of binding a license to a device, also known as node-locking. License Activation requires:

- HardwareID
- The license authorization method (either a license key, or user identification like email / password or Single Sign On)
- The product code

### Hardware ID

This is a unique identifier of a device that activated a license, and is sent on almost all requests to the license API.

## LicenseSpring's RESTful APIs

There are two primary RESTful APIs maintained to interface between LicenseSpring and your product and technology:

:::ExpandableHeading
### License API

The License API is what your client-facing application will use to connect to LicenseSpring's cloud. It allows for a limited set of operations such as license checks, activations, or to count consumptions. It uses a signing and verifying key in order to communicate with the server securely.
:::

:::ExpandableHeading
### Management API

The Management API is intended for all of your back office operations, such as creating new licenses, exporting license usage to a BI tool, or integrating with your internal ERP, CRM, or Recurring billing for instance. It is not intended to be customer facing.
:::

## LicenseSpring's SDKs

We have developed and maintain several wrappers to the APIs to make it easier to add LicenseSpring to your software, as well as to make it easier to use. For example the SDKs will automatically compute the hardwareID, enable local license checks, prevent clock tampering, or cache consumptions, to name a few of the additional features that the SDKs provide.

## Events & Webhooks

### Events API

**At a Glance**
The Events API provides real-time notifications of important actions and changes within the LicenseSpring system, such as new customer creation, license activations, or license expirations. These events form the foundation for building automations, integrations, and custom workflows.

**Technical Overview**

- Events are generated automatically whenever key actions occur (e.g., customer creation, order updates, license lifecycle changes).
- These events are dispatched in real time and can be consumed directly by your applications.
- Events power downstream services such as **webhooks**, enabling external systems to respond promptly.
- Common use cases include integrating with CRMs, automating internal operations, or triggering user engagement flows.

### Webhooks

**At a Glance**
Webhooks provide a simple way for LicenseSpring to notify your systems about events as they happen. Instead of polling APIs, your application receives HTTPS requests containing event details in JSON format, making it easier to stay in sync with license activity.

**Technical Overview**

- You configure a webhook endpoint (listener URL) within your LicenseSpring account.
- You select which events you want to subscribe to (e.g., license created, license expired, customer added).
- When those events occur, LicenseSpring automatically sends an HTTPS POST request with a JSON payload to your endpoint.
- Your system can then parse and act on the event—such as updating records, sending alerts, or triggering workflows.

:::hint{type="info"}
To set up and configure webhooks, click the link for detailed instructions: [**Webhooks**](https://app.archbee.com/docs/FbT_Z5Cu33D-LVZx1fRkU/BvDXPlH6tPa_HUAjp-Ku7)
:::

## &#x20;Integrations&#x20;

LicenseSpring connects seamlessly with leading platforms to streamline licensing operations and boost efficiency.

- **Salesforce:** Manage customer relationships and licensing data in one place while gaining actionable insights.
- **FastSpring:** Automate license provisioning, order processing, and subscription management for smoother operations.
- **Stripe:** Simplify payment handling, subscription billing, and secure financial transactions.
- **Shopify:** Easily manage licenses within your online store, making product monetization simple.

**Why Choose LicenseSpring Integrations?**

- **Ease of Use:** Simple setup for quick adoption.
- **Efficiency:** Reduce manual work and improve productivity.
- **Scalability:** Works for both startups and large enterprises.
- **Reliability:&#x20;**&#x53;ecure, well-maintained integrations you can trust.&#x20;

:::hint{type="info"}
Find an up-to-date list of native integrations supported by LicenseSpring, along with detailed setup instructions, here: [**Integrations**](https://docs.licensespring.com/integrationsx1fRkU/3FzhADO9VUJeNSYeMrEzC)[**&#xA;**](https://docs.licensespring.com/integrations)
:::


[title] Analytics
[path] Vendor Platform/

LicenseSpring offers powerful analytics tools that provide valuable insights into software license usage and customer behavior.&#x20;

## What LicenseSpring Currently Offers

### Comprehensive License API Call Tracking

LicenseSpring's analytics tracks various license-related API calls, including license checks, activations, deactivations, trial keys, orders, licenses issued, and license key generations.&#x20;

This real-time data provides vendors with an in-depth understanding of license usage patterns.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/PJWxiic_snrrl172Z7l9V_image.png)

### &#xD;&#xD;Offline Activations and Deactivations

LicenseSpring's analytics also captures data on offline license activations and deactivations, allowing vendors to account for licenses used in environments without internet connectivity.

### &#xD;&#xD;License and Feature Consumption Tracking

LicenseSpring's analytics monitors license and feature consumptions, helping vendors identify the popularity of specific features and optimize their product offerings.

The analytics feature also highlights licenses or products that have reached their maximum feature usage, aiding vendors in making informed decisions about feature allocation and pricing.

### &#xD;&#xD;Product Details and Versions

Vendors can access detailed information about their products, including different versions and installation files.&#x20;

This insight aids in understanding product adoption and version distribution.


### &#xD;&#xD;

### &#xD;&#xD;Custom Date Range Selection

Vendors can customize the date range for viewing analytics data, enabling them to analyze trends, seasonal variations, and performance over specific periods.

### &#xD;&#xD;Success/Error Rate of API Calls

LicenseSpring's analytics provides success and error rate metrics for API calls, helping vendors monitor system performance and identify potential issues.

### &#xD;&#xD;Detailed Reports for Licenses, Orders, Products, and Customers

LicenseSpring allows vendors to generate detailed reports for each specific license, order, product, or customer.&#x20;

This facilitates granular analysis of API calls associated with individual entities.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/qqoM1SunNZGrGrYF-nPQk_image.png)

### Usage Reports

LicenseSpring provides comprehensive usage reports for individual licenses, giving users valuable insights into how their software is being utilized by end-users.&#x20;

These usage reports offer a detailed overview of license activations, deactivations, and usage patterns, helping software vendors monitor the popularity and distribution of their products.&#x20;

By analyzing individual license data, developers can make informed decisions to optimize their licensing models, identify potential licensing misuse or abuse, and tailor their software offerings to meet customer demands effectively.&#x20;

## Comprehensive List of Tracked Events:

LicenseSpring tracks many events, including:

- License Checks
- License Activation
- License Deactivation
- License Offline Activation
- License Offline Deactivation
- License Trial Key
- Order Created
- License Issued
- License Key Generation
- License Consumption
- License Feature Consumption
- Installation File
- Versions
- Floating Release
- Floating Borrow
- Product Details
- Track Device Variables
- Get Device Variables
- Change Password
- Customer License Users
- Ping
- Single Sign On (SSO)

### &#xD;&#xD;

## **How to Use LicenseSpring Analytics:**

Using LicenseSpring's analytics is straightforward and user-friendly:

1. **Accessing the Analytics Dashboard:&#x20;**&#x4C;og in to your LicenseSpring vendor account and navigate to the analytics dashboard.
2. **Selecting Data Parameters:&#x20;**&#x43;hoose the desired data parameters for analysis, such as license activations, usage frequency, customer segments, etc.
3. **Generating Reports:&#x20;**&#x47;enerate customized reports and view visual representations of the analytics data on the dashboard.
4. **Interpreting Insights:&#x20;**&#x49;nterpret the insights from the analytics data to make informed business decisions, optimize licensing strategies, and improve customer experience.
5. **Taking Action:&#x20;**&#x42;ased on the analytics findings, take proactive actions to address licensing compliance issues, engage with customers, and enhance software offerings.

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/lGESNiSY7Qy4_8mZuy6aq_image.png "LicenseSpring Analytics Dashboard")

By leveraging LicenseSpring's analytics capabilities, vendors can gain valuable intelligence to drive business growth, strengthen customer relationships, and maximize the value of their software licenses.

[title] Email Notifications
[path] Vendor Platform/Settings/

## What Are Email Notifications in LicenseSpring?

LicenseSpring allows the software vendor to send email notifications triggered by specific events to designated recipients. The content of these emails can be customized, as well as the sender email.

You can find the notification configurator in the vendor platform, under "Settings" > "Notifications"

![Notifications Configurer Location](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/9KyJml4OGna3e5qfHnFvc_image.png "Notifications Configurer Location")

::embed[]{url="https://youtu.be/8CikF9Mym0I"}

## What Email Notifications Are Available?

The email notifications that we currently offer are:

1. **Order created  (or appended)** - An order was created or a license was appended to an existing order. Order/license information is sent out by email
2. **License has expired** - Expiration day of license is no longer valid, email is sent at 00:10 UTC
3. **License will expire&#x20;**- Email notification intended to inform recipients of a license that is about to expire. It can be configured to be sent at different time intervals. email is sent 00:10 UTC
4. **Assigned license user** - A user was assigned to a license (user-based licenses only)
5. **Assigned license manager** - A license manager was assigned to an order
6. **Payment method added** -  A user of the vendor platform added a new payment method to the LicenseSpring account
7. **Payment method removed** - A user of the vendor platform removed a new payment method to the LicenseSpring account
8. **Charge succeeded&#x20;**- When the credit card on file in the vendor platform is charged, we can send out this notification to specified recipients.
9. **Invoice finalized&#x20;**- After successful charge in email is sent invoice notification to specified recipients
10. **Trial created -&#x20;**&#x54;riggered when a new trial is initiated.
11. **Trial expired -&#x20;**&#x54;riggered when the trial period has ended.
12. **Trial will expire -&#x20;**&#x54;riggered when the trial period is about to end (with advance warning, typically a few days before expiration).
13. **Assign license user is close to limit -&#x20;**&#x54;riggered when the system is about to assign the maximum number of users allowed under the license (indicating it's near the limit).
14. **Assigned max license users -&#x20;**&#x54;riggered when the maximum number of users allowed for the license is reached.
15. **Maintenance expired -** Triggered when maintenance or support associated with the license has expired.
16. **Maintenance will expire -&#x20;**&#x54;riggered when maintenance or support is about to expire (usually with a set warning period).
17. **Feature expired -&#x20;**&#x54;riggered when a feature associated with the license has expired.
18. **Feature will expire -&#x20;**&#x54;riggered when a feature is about to expire soon (with a predefined warning period).
19. **License activated** - Triggered when a license is successfully activated.

:::hint{type="info"}
[**Contact us**](https://licensespring.zendesk.com/hc/en-us/requests/new) if there is a specific notification you would like to see and we will try to add it!
:::

## Customize the Notification Policy

Each email policy will have slightly different configuration options. To edit the policy, click on the pencil on the row:



![Edit Notification Policy Button](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/aNX-6HRdYo2Ub9EquQXnE_image.png "Edit Notification Policy Button")

### Customizing the Recipients

When editing the policy, you can select the following recipients (depending on the policy, some of these recipients may or may not be available):

- Customer, based on the email specified for that customer
- License user, for user based licenses
- License manager, if they are assigned to a given order
- Company users, as specified in the vendor platform
- Custom recipients, if you would like a certain email address to receive an email notification.

### Customize When to Send Reminder Notifications

The "License will expire" notification allows you to send an email a certain number of days before the license expired to desired recipients. You can specify several days prior to expiry that you would like for the email notification to be sent out:





![Setting Check Days to Remind Users of Expiring Maintenance License](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/dVlV05Pquxv2RPM5cL8vx_image.png "Setting Check Days to Remind Users of Expiring Maintenance License")

The logo that appears on the emails can be set under "Settings" > "Portal Configuration"

For content changes, click on the "emails" tab, and then select the notification you wish to modify.

Content that can be altered in the template:

- Message subject
- Title
- Text
- Fields (different fields are available depending on the email notification you are looking to send)
- Accent color

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ZRZOadEQK-EqUypT2HWD5_image.png)



- **Overview**: Users can preview and edit email notifications for events.
- **Steps**:
  1. Go to **Emails Settings**.
  2. Select an event.
  3. On the right is **Preview** to view the email.
  4. Edit the content on left side if needed, then click **Save**.
- **Overview**: Test emails can be sent to verify the content before live notifications are enabled.
- **Steps**:
  1. Select an event.
  2. If you're satisfied with the appearance and content of the email.
  3. Enter an email address and click **Send** to receive a test notification.

![Test email notification](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/5QSekrmVfvvkIo-1KMpVn_image.png "Test email notification")


[title] Time-Limited vs Subscription Licenses
[path] License Entitlements/License Types/

There are important distinctions between a time-limited license and a subscription license. Although they both hold a validity period, they don't work the same way. One license type might be more appropriate to use than another depending on how you wish to enforce your licensing.

## Distinctions Between Time-Limited and Subscription Licenses

There are a few key distinctions:

| Distinction         | Time-Limited                                                                                                                                                               | Subscription                                                                                                                                                                                                 |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| License Status      | Assuming the license is enabled, the license status will be `inactive` if the total activations of the license is 0, and `active`  if total activations is greater than 0. | The status does not depend on total activations. It will be `active` when the license is created, and will only be `disabled`  if the source of truth communicates that the subscription has been cancelled. |
| Offline Activations | Possible by sending a license refresh file                                                                                                                                 | Not possible.                                                                                                                                                                                                |
| Grace Period        | Not implemented at the moment                                                                                                                                              | You can define number of hours after which the license will be still valid ( `is_expired` will be `false`  ) even if `validity_period` is expired                                                            |

Time-limited licenses need to be extended manually or using management api and subscriptions should rely on some 3rd party service as a source of truth.

## When to Use Time-Limited Licenses

- If you were issuing a recurring license that is for use on machines that do not have access to the internet. In this case, you can activate licenses offline, and simply resend a refreshed license file.
- You want to ensure a license expires unless it's validity period is specifically renewed.

## When to Use a Subscription Licenses

The only time you would use this is if you were using an external source of truth to maintain subscription status. This external source of truth is typically a recurring billing system or a CRM.




[title] Portals
[path] /

For parties external to the software vendor, we make available a range of interfaces, including a set of portals.&#x20;

LicenseSpring's portals can be configured to allow license management by an external third party.&#x20;

Some common tasks that can be done via the portals include the following:

- Assign/unassign users to a license
- Transfer a license from one device to another
- Look up licenses from an order and dispatch them across the organization
- Issue new licenses for an existing order without the intervention of the software vendor
- Activate or deactivate licenses for computers that do not have access to the internet
- Reset licenses

## Available Portals

LicenseSpring currently maintains 3 portals (not including the Vendor platform):

:::hint{type="info"}
All of our portals, including the API, can be white-labeled to a vendor's subdomain. For more details, please contact us directly.
:::

### User Portal

URL: [**users.licensespring.com**](https://users.licensespring.com)

License managers can log in to this portal and manage licenses for all of the orders they have been assigned to, according to the permissions they have been given.

### Offline Activation Portal

URL: [**offline.licensespring.com**](https://offline.licensespring.com/)

End users can activate and deactivate their licenses the offline activation method using this portal.

### Air-Gapped Activation Portal

URL: [**airgap.licensespring.com**](https://airgap.licensespring.com/)

End users can activate and deactivate their licenses that are air-gapped using this portal.

[title] Activate License (Offline Method)
[path] License API/License Activation/Deactivation/

:::hint{type="info"}
Currently we support trial, perpetual and consumption license types for offline activation purposes
:::

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/activate_offline",
  "name": "/api/v4/activate_offline",
  "method": "POST",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [
      {
        "name": "base64-encoded JSON object",
        "kind": "required",
        "type": "Object",
        "description": "The request body is a base64-encoded stringified JSON object containing the properties below. See the \"Finalized payload\" section for examples on how to generate this payload",
        "children": [
          {
            "name": "api_key OR client_id",
            "kind": "required",
            "type": "string",
            "description": "Authorization parameter used for the request, either `api_key` if using API key-based authorization, or `client_id` if using SSO authorization"
          },
          {
            "name": "date",
            "kind": "required",
            "type": "string",
            "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
          },
          {
            "name": "request_id",
            "kind": "required",
            "type": "string",
            "description": "Custom unique ID used to identify the request"
          },
          {
            "name": "request",
            "kind": "required",
            "type": "string",
            "description": "Determines the type of request: \"activation\" or \"deactivation\""
          },
          {
            "name": "signature",
            "kind": "required",
            "type": "string",
            "description": "Calculated request signature (see section below)"
          },
          {
            "name": "product",
            "kind": "required",
            "type": "string",
            "description": "Product short code"
          },
          {
            "name": "hardware_id",
            "kind": "required",
            "type": "string",
            "description": "Unique hardware ID generated for the client device"
          },
          {
            "name": "license_key",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is key-based (see section below)"
          },
          {
            "name": "username",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is user based (see section below)"
          },
          {
            "name": "password",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is user based (see section below)"
          },
          {
            "name": "license_id",
            "kind": "optional",
            "type": "Number",
            "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user"
          },
          {
            "name": "os_ver",
            "kind": "optional",
            "type": "string",
            "description": "Operating System description string which will be stored in license device data"
          },
          {
            "name": "hostname",
            "kind": "optional",
            "type": "string",
            "description": "Hostname string which will be stored in license device data"
          },
          {
            "name": "os_hostname",
            "kind": "optional",
            "type": "string",
            "description": "Legacy version of \"hostname\" parameter (see above)"
          },
          {
            "name": "ip",
            "kind": "optional",
            "type": "string",
            "description": "Client IP address string which will be stored in license device data"
          },
          {
            "name": "ip_local",
            "kind": "optional",
            "type": "string",
            "description": "Legacy version of \"ip\" parameter (see above)"
          },
          {
            "name": "app_ver",
            "kind": "optional",
            "type": "string",
            "description": "Application version string which will be stored in license device data"
          },
          {
            "name": "sdk_ver",
            "kind": "optional",
            "type": "string",
            "description": "SDK version string which will be stored in license device data"
          },
          {
            "name": "mac_address",
            "kind": "optional",
            "type": "string",
            "description": "Client MAC address which will be stored in license device data"
          },
          {
            "name": "variables",
            "kind": "optional",
            "type": "Object",
            "description": "Stores device variables. Variables are sent as a JSON object where the key is the variable name, and the value is the value of the variable",
            "children": []
          }
        ],
        "schema": [
          {
            "name": "api_key OR client_id",
            "kind": "required",
            "type": "string",
            "description": "Authorization parameter used for the request, either `api_key` if using API key-based authorization, or `client_id` if using SSO authorization"
          },
          {
            "name": "date",
            "kind": "required",
            "type": "string",
            "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
          },
          {
            "name": "request_id",
            "kind": "required",
            "type": "string",
            "description": "Custom unique ID used to identify the request"
          },
          {
            "name": "request",
            "kind": "required",
            "type": "string",
            "description": "Determines the type of request: \"activation\" or \"deactivation\""
          },
          {
            "name": "signature",
            "kind": "required",
            "type": "string",
            "description": "Calculated request signature (see section below)"
          },
          {
            "name": "product",
            "kind": "required",
            "type": "string",
            "description": "Product short code"
          },
          {
            "name": "hardware_id",
            "kind": "required",
            "type": "string",
            "description": "Unique hardware ID generated for the client device"
          },
          {
            "name": "license_key",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is key-based (see section below)"
          },
          {
            "name": "username",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is user based (see section below)"
          },
          {
            "name": "password",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is user based (see section below)"
          },
          {
            "name": "license_id",
            "kind": "optional",
            "type": "Number",
            "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user"
          },
          {
            "name": "os_ver",
            "kind": "optional",
            "type": "string",
            "description": "Operating System description string which will be stored in license device data"
          },
          {
            "name": "hostname",
            "kind": "optional",
            "type": "string",
            "description": "Hostname string which will be stored in license device data"
          },
          {
            "name": "os_hostname",
            "kind": "optional",
            "type": "string",
            "description": "Legacy version of \"hostname\" parameter (see above)"
          },
          {
            "name": "ip",
            "kind": "optional",
            "type": "string",
            "description": "Client IP address string which will be stored in license device data"
          },
          {
            "name": "ip_local",
            "kind": "optional",
            "type": "string",
            "description": "Legacy version of \"ip\" parameter (see above)"
          },
          {
            "name": "app_ver",
            "kind": "optional",
            "type": "string",
            "description": "Application version string which will be stored in license device data"
          },
          {
            "name": "sdk_ver",
            "kind": "optional",
            "type": "string",
            "description": "SDK version string which will be stored in license device data"
          },
          {
            "name": "mac_address",
            "kind": "optional",
            "type": "string",
            "description": "Client MAC address which will be stored in license device data"
          },
          {
            "name": "variables",
            "kind": "optional",
            "type": "Object",
            "description": "Stores device variables. Variables are sent as a JSON object where the key is the variable name, and the value is the value of the variable",
            "children": []
          }
        ]
      }
    ],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "es8g1cuKJMbNPiIVt9VoF",
        "code": "{\n  \"request\": \"activation\",\n  \"license_key\": \"GAWDA-BMRZ-YWEL-3KTP\",\n  \"username\": \"test@example.com\",\n  \"request_id\": \"4D75-4BB1-98B3-FD58B705B52E\",\n  \"license_signature\": \"2/7gGLn1HHvmrVCHXo=\",\n  \"validity_period\": null,\n  \"maintenance_period\": \"2029-10-24T00:00:00.000Z\",\n  \"license_type\": \"perpetual\",\n  \"is_trial\": false,\n  \"product_features\": [{\n          \"name\": 'feature 3',\n          \"code\": 'F3',\n          \"feature_type\": 'activation',\n          \"allow_overages\": false,\n          \"max_overages\": 0,\n          \"expiry_date\": '2022-02-25'\n      },\n      {\n          \"name\": 'feature 4',\n          \"code\": 'F4',\n          \"feature_type\": 'consumption',\n          \"max_consumption\": 10,\n          \"total_consumptions\": 0,\n          \"expiry_date\": null\n      }\n  ],\n  \"max_activations\": 1,\n  \"times_activated\": 0,\n  \"custom_fields\": [\n    {\n      \"name\": \"custom field\",\n      \"data_type\": null,\n      \"value\": \"has a value\"\n    },\n    {\n      \"name\": \"TestFieldName\",\n      \"data_type\": null,\n      \"value\": \"TestFieldValue\"\n    }\n  ],\n  \"product details\": {\n    \"product_name\": \"Test\",\n    \"short_code\": \"TT\",\n    \"allow_trial\": true,\n    \"trial_days\": 15,\n    \"authorization_method\": \"license-key\",\n    \"allow_overages\": true,\n    \"max_overages\": 10\n  }\n}",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "7eyIlKSv2QgJcowEsDZ-2",
        "code": "",
        "language": "400",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "es8g1cuKJMbNPiIVt9VoF"
  },
  "examples": {
    "languages": [
      {
        "id": "MVswmprxv53Y8L_yhrmmd",
        "language": "curl",
        "code": "curl --location --request POST '/api/v4/activate_offline' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string' \\\n--data-raw '_BASE64_PAYLOAD_HERE_'",
        "customLabel": ""
      },
      {
        "id": "ZCTQO7_LVyOjAVX7pP4kO",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'POST',\n   'url': '/api/v4/activate_offline',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   },\n   body: Buffer.from(JSON.stringify(offline_payload)).toString('base64')\n};\n\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "LI5XFmSVTa4QEJC9tahg2",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: btoa(JSON.stringify(offline_payload)),\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/activate_offline\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "cmQNdWH3b3clWrX7G_IxJ",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/activate_offline\"\n\npayload = \"{\\\"Payload\\\":\\\"Object\\\"}\"\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "i6V2Wf-nI00sMv9ahE5rB",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/activate_offline\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\nrequest.body = \"{\\\"Payload\\\":\\\"Object\\\"}\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "cmQNdWH3b3clWrX7G_IxJ"
  },
  "description": "Activates a license using the offline activation method\n",
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "apiv4activateoffline",
  "legacyHash": "QO5GDP0RzYbnGkCFOCK7Y"
}
```
:::

## Schema

### Request Body

The request body is a string representing a base64-encoded JSON object containing all the required activation data.

:::hint{type="danger"}
If using "multipart/form-data" for the request, the "file" form parameter is mandatory
:::

:::CodeblockTabs
```typescript
type LicenseOfflineActivationObject = ({

  // for key-based licenses:
  license_key: string

} | {

  // for user-based licenses:
  username: string
  password: string

}) & {

  // required properties:
  hardware_id: string
  product: string
  request_id: string
  signature: string
  date: string
  request: "activation"

} & ({
  api_key: string // for API key authorization
} | {
  client_id: string // for OAuth authorization
}) & {

  // optional properties:
  bundle_code?: string | undefined
  license_id?: number | undefined
  is_vm?: boolean | undefined
  vm_info?: string | undefined
  os_ver?: string | undefined
  hostname?: string | undefined
  os_hostname?: string | undefined
  ip?: string | undefined
  ip_local?: string | undefined
  app_ver?: string | undefined
  sdk_ver?: string | undefined
  mac_address?: string | undefined
  variables?: { [key: string]: string } | undefined
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "allOf": [
    {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "license_key": { "type": "string" }
          },
          "required": ["license_key"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "username": { "type": "string" },
            "password": { "type": "string" }
          },
          "required": ["username", "password"],
          "additionalProperties": false
        }
      ]
    },
    {
      "type": "object",
      "properties": {
        "api_key": { "type": "string" },
        "client_id": { "type": "string" },
        "request": { "type": "string" },
        "request_id": { "type": "string" },
        "date": { "type": "string" },
        "signature": { "type": "string" },
        "hardware_id": { "type": "string" },
        "product": { "type": "string" },
        "bundle_code": { "type": "string" },
        "license_id": { "type": "number" },
        "is_vm": { "type": "boolean" },
        "vm_info": { "type": "string" },
        "os_ver": { "type": "string" },
        "hostname": { "type": "string" },
        "os_hostname": { "type": "string" },
        "ip": { "type": "string" },
        "ip_local": { "type": "string" },
        "app_ver": { "type": "string" },
        "sdk_ver": { "type": "string" },
        "mac_address": { "type": "string" },
        "variables": {
          "type": "object",
          "additionalProperties": { "type": "string" }
        }
      },
     "allOf": [
        { "anyOf": [{ "required": ["api_key"] }, { "required": ["client_id"] }] },
        { "anyOf": [{ "required": ["license_key"] }, { "required": ["username", "password"] }] }
      ],
      "required": ["hardware_id", "product", "date", "signature"],
      "additionalProperties": false
    }
  ]
}
```
:::

### Signature

The `signature` value is constructed as follows:

1. The string `licenseSpring` plus a newline
2. The string `date`, plus the "date" value from the license payload object, plus a newline
3. Either the "license\_key" or "username" value from the request payload object (which ever is present on the license, see the License Authorization Method section below) plus a newline
4. The "hardware\_id" value from the request payload object plus a newline
5. The "api\_key" value from the request payload object

This complete string is then encrypted using **HMAC-SHA256** and the company **shared key** as the encryption key.

```javascript
import crypto from 'node:crypto';

const activationPayload = {
  // ...payload content...
};

// api_key or client_id depending on authorization type used:
const key = (activationPayload.api_key || activationPayload.client_id);

// if using API key authorization: the signing key is the Shared Key
// if using OAuth: the signing key is the Client Secret
const signingKey = '...';

const signingString =
  'licenseSpring\n' +
  'date: ' + activationPayload.date + '\n' +
  (activationPayload.license_key || activationPayload.username) + '\n' +
  activationPayload.hardware_id + '\n' +
  key;

  const signature = crypto
    .createHmac('sha256', signingKey)
    .update(signingString)
    .digest('base64');
```

### Finalized payload

This object is then stringified and encoded to base64, e.g.:

:::CodeblockTabs
JS Browser

```javascript
const activationPayload = {
  // ...payload content...
};
const requestBody = btoa(JSON.stringify(activationPayload));
```

nodeJS

```javascript
const activationPayload = {
  // ...payload content...
};
const requestBody = Buffer.from(JSON.stringify(activationPayload)).toString('base64');
```
:::

### Response Body

:::CodeblockTabs
```typescript
type LicenseActivationResponseBody = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  borrowed_until: string | null,
  can_borrow: boolean,
  device_id: number,
  enable_maintenance_period: boolean
  floating_timeout: number,
  grace_period: number,
  is_air_gapped: boolean,
  is_borrowed: boolean,
  is_expired: boolean,
  is_floating_cloud: boolean,
  is_floating: boolean,
  is_hardware_key_auth: boolean,
  license_active: boolean,
  license_enabled: boolean,
  license_signature: string,
  license_signature_v2: string,
  offline_signature: string,
  license_type: string,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users: number,
  max_overages: number,
  max_transfers: number,
  order_store_id: string,
  prevent_vm: boolean,
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null, // string is in DateISO8601UTC format
  company: { id: number },
  installation_file_id: number | null,
  installation_file: null | {
    id: number,
    channel: string,
    environment: string,
    eula_link: string,
    hash_md5: string,
    installation_file: string,
    release_date: string | null,
    release_notes_link: string,
    requires_version: string | null,
    size: string | null,
    version: string,
  },
  product_features: ({
    id: number,
    code: string,
    name: string,
    expiry_date: string,
    metadata: JSON,
    feature_type: 'activation' | 'consumption',
    is_floating: boolean,
    is_floating_cloud: boolean,

    // the following properties are only present if is_floating=true or is_floating_cloud=true
    floating_users: number,
    floating_timeout: number,

    // the following properties are only present if feature_type=consumption
    max_consumption: number,
    allow_unlimited_consumptions: boolean,
    total_consumptions: number,
    allow_overages: number,
    max_overages: number,
    reset_consumption: boolean,
    consumption_period: 'daily' | 'weekly' | 'monthly' | 'annualy' | null,
    can_borrow: boolean,
    max_borrow_time: number,
  })[],
  
  custom_fields: ({
    name: string,
    data_type: 'numer' | 'text' | 'date/time',
    value: string,
  })[],
  
  customer: {
    email: string,
    company_name: string,
    reference: string,
    phone: string,
    first_name: string,
    last_name: string,
    city: string,
    postcode: string,
    state: string,
    country: string,
    address: string,
    customer_account: string | null,
    metadata: JSON,
  },
  
  product_details: {
    product_id: number,
    product_name: string,
    short_code: string,
    authorization_method: 'license-key' | 'user',
    metadata: JSON,
  },
  
  metadata: JSON,
  
  // the following property is only present if is_trial=true
  trial_days: number,
  
  // the following properties is only present if is_floating=true or is_floating_cloud=true
  floating_in_use_devices: number,
  floating_users: number,
  
  // the following properties are only present if license_type='consumption'
  max_consumptions: number,
  total_consumptions: number,
  allow_unlimited_consumptions: boolean,
  reset_consumption: boolean,
  consumption_period: string | null, // string is in DateISO8601UTC format
  
} & ({

  // for key-based licenses:
  license_key: string,

} | {

  // for user-based licenses:
  user: {
    id: number,
    email: string,
    first_name: string,
    last_name: string,
    phone_number: string,
    is_initial_password: boolean,
    max_activations: number,
    allow_unlimited_activations: boolean,
    total_activations: number
  }
});

```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "allOf": [
    {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "license_key": { "type": "string" }
          },
          "required": ["license_key"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "user": {
              "type": "object",
              "properties": {
                "id": { "type": "number" },
                "email": { "type": "string" },
                "first_name": { "type": "string" },
                "last_name": { "type": "string" },
                "phone_number": { "type": "string" },
                "is_initial_password": { "type": "boolean" },
                "max_activations": { "type": "number" },
                "allow_unlimited_activations": { "type": "boolean" },
                "total_activations": { "type": "number" }
              },
              "required": ["id", "email", "first_name", "last_name", "phone_number", "is_initial_password", "max_activations", "allow_unlimited_activations", "total_activations"],
              "additionalProperties": false
            }
          },
          "required": ["user"],
          "additionalProperties": false
        }
      ]
    },
    {
      "type": "object",
      "properties": {
        "id": { "type": "number" },
        "allow_grace_period": { "type": "boolean" },
        "allow_overages": { "type": "boolean" },
        "allow_unlimited_activations": { "type": "boolean" },
        "borrowed_until": { "type": ["string", "null"] },
        "can_borrow": { "type": "boolean" },
        "device_id": { "type": "number" },
        "enable_maintenance_period": { "type": "boolean" },
        "floating_timeout": { "type": "number" },
        "grace_period": { "type": "number" },
        "is_air_gapped": { "type": "boolean" },
        "is_borrowed": { "type": "boolean" },
        "is_expired": { "type": "boolean" },
        "is_floating_cloud": { "type": "boolean" },
        "is_floating": { "type": "boolean" },
        "is_hardware_key_auth": { "type": "boolean" },
        "license_active": { "type": "boolean" },
        "license_enabled": { "type": "boolean" },
        "license_signature": { "type": "string" },
        "license_signature_v2": { "type": "string" },
        "offline_signature": { "type": "string" },
        "license_type": { "type": "string" },
        "maintenance_period": { "type": ["string", "null"] },
        "max_activations": { "type": "number" },
        "max_borrow_time": { "type": "number" },
        "max_license_users": { "type": "number" },
        "max_overages": { "type": "number" },
        "max_transfers": { "type": "number" },
        "order_store_id": { "type": "string" },
        "prevent_vm": { "type": "boolean" },
        "start_date": { "type": ["string", "null"] },
        "times_activated": { "type": "number" },
        "transfer_count": { "type": "number" },
        "validity_period": { "type": ["string", "null"] },
        "installation_file_id": { "type": ["number","null"] },
        "installation_file": {
            "type": "object",
            "properties": {
                "version": { "type": ["string", "null"] },
                "environment": { "type": "string" },
                "hash_md5": { "type": ["string", "null"] },
                "eula_link": { "type": ["string", "null"] },
                "release_notes_link": { "type": ["string", "null"] },
                "size": { "type": ["string", "null"] },
                "requires_version": { "type": ["string", "null"] },
                "channel": { "type": ["string", "null"] },
                "installation_file": { "type": ["string", "null"] },
                "release_date": { "type": ["string", "null"] }
            }
        },
        "company": { "type": "object", "properties": {"id": { "type": "number" } } },
        "product_features": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": { "type": "number" },
              "code": { "type": "string" },
              "name": { "type": "string" },
              "expiry_date": { "type": "string" },
              "metadata": {},
              "feature_type": { "type": "string", "enum": ["activation", "consumption"] },
              "is_floating": { "type": "boolean" },
              "is_floating_cloud": { "type": "boolean" },
              "floating_users": { "type": "number" },
              "floating_timeout": { "type": "number" },
              "max_consumption": { "type": "number" },
              "allow_unlimited_consumptions": { "type": "boolean" },
              "total_consumptions": { "type": "number" },
              "allow_overages": { "type": "number" },
              "max_overages": { "type": "number" },
              "max_borrow_time": { "type": "number" },
              "can_borrow": { "type": "boolean" },
              "reset_consumption": { "type": "boolean" },
              "consumption_period": {
                "type": ["string", "null"],
                "enum": ["daily", "weekly", "monthly", "annualy", null]
              }
            },
            "required": ["id", "code", "name", "expiry_date", "metadata", "feature_type", "is_floating", "is_floating_cloud"]
          }
        },
        "custom_fields": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "name": { "type": "string" },
              "data_type": { "type": "string", "enum": ["numer", "text", "date/time"] },
              "value": { "type": "string" }
            },
            "required": ["name", "data_type", "value"]
          }
        },
        "customer": {
          "type": "object",
          "properties": {
            "email": { "type": "string" },
            "company_name": { "type": "string" },
            "reference": { "type": "string" },
            "phone": { "type": "string" },
            "first_name": { "type": "string" },
            "last_name": { "type": "string" },
            "city": { "type": "string" },
            "postcode": { "type": "string" },
            "state": { "type": "string" },
            "country": { "type": "string" },
            "address": { "type": "string" },
            "customer_account": { "type": ["string", "null"] },
            "metadata": {}
          },
          "required": ["email", "company_name", "reference", "phone", "first_name", "last_name", "city", "postcode", "state", "country", "address", "metadata"]
        },
        "product_details": {
          "type": "object",
          "properties": {
            "product_id": { "type": "number" },
            "product_name": { "type": "string" },
            "short_code": { "type": "string" },
            "authorization_method": { "type": "string", "enum": ["license-key", "user"] },
            "metadata": {}
          },
          "required": ["product_id", "product_name", "short_code", "authorization_method", "metadata"]
        },
        "metadata": {},
        "trial_days": { "type": "number" },
        "floating_in_use_devices": { "type": "number" },
        "floating_users": { "type": "number" },
        "max_consumptions": { "type": "number" },
        "total_consumptions": { "type": "number" },
        "allow_unlimited_consumptions": { "type": "boolean" },
        "reset_consumption": { "type": "boolean" },
        "consumption_period": { "type": ["string", "null"] }
      },
      "required": [
        "id",
        "allow_grace_period",
        "allow_overages",
        "allow_unlimited_activations",
        "can_borrow",
        "channel",
        "device_id",
        "enable_maintenance_period",
        "environment",
        "eula_link",
        "floating_timeout",
        "grace_period",
        "hash_md5",
        "installation_file",
        "is_air_gapped",
        "is_borrowed",
        "is_expired",
        "is_floating_cloud",
        "is_floating",
        "is_hardware_key_auth",
        "license_active",
        "license_enabled",
        "license_signature",
        "license_signature_v2",
        "offline_signature",
        "license_type",
        "max_activations",
        "max_borrow_time",
        "max_license_users",
        "max_overages",
        "max_transfers",
        "order_store_id",
        "prevent_vm",
        "release_date",
        "release_notes_link",
        "requires_version",
        "size",
        "times_activated",
        "transfer_count",
        "version",
        "product_features",
        "custom_fields",
        "customer",
        "product_details",
        "metadata"
      ],
      "additionalProperties": false
    }
  ]
}
```
:::

### Response Signature

The response objects two digital signatures which the client app can use to verify the authenticty of the response:

1. `license_signature` is the HMAC-SHA256 signature explained in the [**Response Signature**](docId\:ouciGcAGCAIKAdWCbx9Wk) article
2. `offline_signature` is an additional HMAC-SHA256 signature specific to this endpoint. This value is constructed identically to the `signature` parameter in the request payload (see [**Activate License (Offline Method)**](docId\:H_VEWmE7rYJ7QfbIKvGuP) above) using the `date` value received in the response

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

### Key-based product licenses

Each license assigned to the product requires the client to provide a license key in order to activate, check or deactivate the license (property `license_key` in the request body).

The license response object will contain the `license_key` property, and the property `product_details.authorization_method` will be the string `license_key`.

### User-based product licenses

Each license assigned to the product has a corresponding "license user" instead of a license key. Requires `username` and `password` to be provided.

In the license response object, `product_details.authorization_method` will have the string value `user` and the response object will contain the `user` object with information on the license user.&#x20;

## License Types

The `license_type` property defines one of the 4 types of licenses based on their duration and how the license is used:

- Perpetual: `perpetual`
- Time-limited: `time-limited`
- Subscription: `subscription`
- Consumption: `consumption`

For more information see: [**License Types**](docId\:xHxttCVj7gs6qeAqu7Cua)&#x20;

## Device variables

The optional `variables` parameter lets you set device variables during activation. For more information on how device variables work, see [**Device Variables**](docId\:r2cnEKm7RUFf-U0JKM0Lw)

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**missing\_headers** (400): some headers are missing
:::

- when missing authorization or date headers

:::BlockQuote
**missing\_parameters** (400): some parameters are missing in the request: different, parameters
:::

- when no request body at all or no file found in request body

:::BlockQuote
**authorization\_missing\_params** (400): some parameters are missing in authorization: different, parameters
:::

- when has request body but request body is not properly base 64 encoded
- when file is missing in request body
- when license\_key or hardware\_id body parameters are missing
- when data body parameter is missing
- when api\_key parameter is missing

:::hint{type="info"}
If you want to use this api endpoint directly, instead of using SDK, which does most of heavy lifting for you, please contact us for additional instructions
:::

## Guide on using Offline Licenses

&#x20;If any aspect of the offline licensing model remains unclear or raises questions, we encourage you to explore our in-depth guide on [**link**](https://docs.licensespring.com/license-entitlements/activation-types/offline)

This resource offers a comprehensive explanation of the offline licensing process, how it operates, and ways to utilize its advantages for your specific software applications&#x20;


[title] Orders
[path] Vendor Platform/

This is summary view that displays a table with order information. Clicking on one of the orders will open the orders summary view.

Actions you can take on the orders summary view Include:

- Search for an order
- Download all orders and licenses for a given date range
- Start the order creator process

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/KLP8NbzK1WCjzE25jL44H_image.png)

The columns you can specify for the orders table are:

- `Created on` Date/time at which an order was created
- `Customer email` If a customer is specified for this order, then the customer's email address will appear in this column
- `Customer name` Customer name if the order has a customer specified
- `Customer company` Company of the customer if the `Order` belongs to a customer with a company field
- `Customer account` Account of the customer if they belong to one, and if the order has a customer specified
- `Customer reference` Customer reference number if one is specified
- `Customer Labels` Customer label if one was specified
- `Order ID` Orders will always have this value
- `Order reference` Optionally specified reference number of the order
- `Last updated` Last time the order information was updated (order reference, campaign parameters, downloadID, is test, or is trial ).
- `Type` If created using a [**Trial Key**](docId\:MtAnOsFYJyXU-2M0OVz_a) License API endpoint it will be set as `api_trial` and in rest of the cases it will be set as `normal`. It can be overwritten using Management API when using the [**Create Order**](docId\:GCoYGuLOy0Np_x03DVcK2) endpoint
- `Campaign parameters` Optional field, currently not used
- `Is trial` If the order was created when generating a trial license via the License API, there will be a green check mark in this field


[title] Check Bundle
[path] License API/License Check/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/check_bundle",
  "name": "/api/v4/check_bundle",
  "method": "GET",
  "request": {
    "pathParameters": [],
    "queryParameters": [
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "string",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "description": "Short code for the bundle product",
        "": "Short code for the bundle product"
      },
      {
        "kind": "optional",
        "name": "license_key",
        "type": "string",
        "children": [],
        "description": "Required if product is key-based (see section below)"
      },
      {
        "kind": "optional",
        "name": "username",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "Number",
        "description": "Ensures that the action affects only the bundle license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "": "Ensures that the action affects only the bundle license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\""
      },
      {
        "name": "include_expired_features",
        "kind": "optional",
        "type": "Boolean",
        "description": "Whether expired product features should be included in the response",
        "children": []
      },
      {
        "name": "env",
        "kind": "optional",
        "type": "String",
        "description": "Checks the licenses status against the specified product installation file environment (matching the installation file's \"environment\" property)",
        "children": []
      },
      {
        "name": "os_ver",
        "kind": "optional",
        "type": "string",
        "description": "Updates license device data, sets Operating System string to this value",
        "children": []
      },
      {
        "name": "hostname",
        "kind": "optional",
        "type": "string",
        "description": "Updates license device data, sets hostname string to this value",
        "children": []
      },
      {
        "name": "os_hostname",
        "kind": "optional",
        "type": "string",
        "description": "Legacy version of \"hostname\" parameter (see above)",
        "children": []
      },
      {
        "name": "ip",
        "kind": "optional",
        "type": "string",
        "description": "Updates license device data, sets IP address string to this value",
        "children": []
      },
      {
        "name": "ip_local",
        "kind": "optional",
        "type": "string",
        "description": "Legacy version of \"ip\" parameter (see above)",
        "children": []
      },
      {
        "name": "app_ver",
        "kind": "optional",
        "type": "string",
        "description": "Updates license device data, sets application version string to this value",
        "children": []
      },
      {
        "name": "sdk_ver",
        "kind": "optional",
        "type": "string",
        "description": "Updates license device data, sets SDK version string to this value",
        "children": []
      },
      {
        "name": "mac_address",
        "kind": "optional",
        "type": "string",
        "description": "Updates license device data, sets MAC address string to this value",
        "children": []
      }
    ],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "QLX3IFr3FPKeqNnhkuAXk",
        "code": "[\n    {\n        \"id\": 1742895176814029,\n        \"order_store_id\": \"0bce1a4470aa495ca53acc5b48377eb3\",\n        \"license_active\": true,\n        \"license_enabled\": true,\n        \"license_type\": \"perpetual\",\n        \"license_key\": \"UCD8-XVHJ-TSRH-W4BO\",\n        \"is_trial\": false,\n        \"max_license_users\": 1,\n        \"validity_period\": null,\n        \"enable_maintenance_period\": false,\n        \"maintenance_period\": null,\n        \"allow_grace_period\": false,\n        \"grace_period\": 0,\n        \"max_activations\": 1,\n        \"allow_unlimited_activations\": false,\n        \"times_activated\": 1,\n        \"start_date\": null,\n        \"transfer_count\": 0,\n        \"max_transfers\": 0,\n        \"allow_overages\": false,\n        \"max_overages\": 0,\n        \"is_floating_cloud\": false,\n        \"is_floating\": false,\n        \"floating_timeout\": 120,\n        \"can_borrow\": false,\n        \"max_borrow_time\": 0,\n        \"prevent_vm\": false,\n        \"custom_fields\": [],\n        \"product_features\": [],\n        \"customer\": {\n            \"email\": \"\",\n            \"company_name\": \"\",\n            \"reference\": \"\",\n            \"phone\": \"\",\n            \"first_name\": \"\",\n            \"last_name\": \"\",\n            \"city\": \"\",\n            \"postcode\": \"\",\n            \"state\": \"\",\n            \"country\": \"\",\n            \"address\": \"\",\n            \"customer_account\": null,\n            \"metadata\": {}\n        },\n        \"product_details\": {\n            \"product_id\": 1586066454419168,\n            \"product_name\": \"Bundle One\",\n            \"short_code\": \"bun1\",\n            \"authorization_method\": \"license-key\",\n            \"metadata\": {}\n        },\n        \"metadata\": {},\n        \"is_hardware_key_auth\": false,\n        \"is_air_gapped\": false,\n        \"device_id\": 1742895188873059,\n        \"is_borrowed\": false,\n        \"borrowed_until\": null,\n        \"is_expired\": false,\n        \"version\": \"\",\n        \"installation_file\": \"\",\n        \"release_date\": \"\",\n        \"hash_md5\": \"\",\n        \"requires_version\": \"\",\n        \"environment\": \"\",\n        \"eula_link\": \"\",\n        \"release_notes_link\": \"\",\n        \"size\": \"\",\n        \"channel\": \"\",\n        \"license_signature\": \"KQfPkJ89kpbIs/T0xcSufU6fVzIoZMgNMuJgXG4eFsl1721aBw7ePl3kSqCQU3+8B200opR6yjdSBuqZw5OAebi/DsspG9UpMHOM38l6C/6BBHc5I1+CL5SvlLvH8/c8/fWNn4XjDd8S0VquK1+qxoukQ2N5QiwYRwHiA0y1X4n1FIYHBO+1MO+WZsdWj4SVkbiBuMWMTrVuNwmHgnSziOU/j4H3Uk5JFZqilJflAdz+jtmvciZkay8CQEKQKHnw0x8M6mWemU1dJaj0pgTeF/CXyQvTZT+9iccYPrrSEgbeeuqVexaT6qJajOjp0XNH/8Eg/eUnYZU8A2mQcZB8i2SAgVlBD9dSTCTrZP7OoJWpWJ91UtNjJ/2VWehaDXGikVF0BfQjkm+d1ZzCt3TWbWffOawxv+M+hjDWIzEkRE0qFARBCX66XT5ftZHBcuNP65vedrpkx+8ZO3jNLonEv2qChBwQcOtrnEC38kPQBkcbBxoCClbbtPp145v30mfYLXB0CudxO00j8uWWnMseg1XwMihrqWN9oDLB2obRdkiDZ/9mKSykVeUOxPTaB7T44AlgnEFki45DO6BH1ZH+cxN0shcrzXZwrpHjczNVSgIVHV4jNdyY47gH+SS/Cn6j9+jQ9IU4kZtEbFmhkTQRXS996YNsc9mFhOh2AIde/WE=\"\n    },\n    {\n        \"id\": 1742895176822039,\n        \"order_store_id\": \"0bce1a4470aa495ca53acc5b48377eb3\",\n        \"license_active\": true,\n        \"license_enabled\": true,\n        \"license_type\": \"perpetual\",\n        \"license_key\": \"UCD8-XVHJ-TSRH-W4BO\",\n        \"is_trial\": false,\n        \"max_license_users\": 1,\n        \"validity_period\": null,\n        \"enable_maintenance_period\": true,\n        \"maintenance_period\": \"2026-03-25T00:00:00.000Z\",\n        \"allow_grace_period\": false,\n        \"grace_period\": 0,\n        \"max_activations\": 1,\n        \"allow_unlimited_activations\": false,\n        \"times_activated\": 1,\n        \"start_date\": null,\n        \"transfer_count\": 0,\n        \"max_transfers\": 0,\n        \"allow_overages\": false,\n        \"max_overages\": 0,\n        \"is_floating_cloud\": false,\n        \"is_floating\": false,\n        \"floating_timeout\": 120,\n        \"can_borrow\": false,\n        \"max_borrow_time\": 0,\n        \"prevent_vm\": false,\n        \"custom_fields\": [],\n        \"product_features\": [],\n        \"customer\": {\n            \"email\": \"\",\n            \"company_name\": \"\",\n            \"reference\": \"\",\n            \"phone\": \"\",\n            \"first_name\": \"\",\n            \"last_name\": \"\",\n            \"city\": \"\",\n            \"postcode\": \"\",\n            \"state\": \"\",\n            \"country\": \"\",\n            \"address\": \"\",\n            \"customer_account\": null,\n            \"metadata\": {}\n        },\n        \"product_details\": {\n            \"product_id\": 2,\n            \"product_name\": \"Test product\",\n            \"short_code\": \"TP\",\n            \"authorization_method\": \"license-key\",\n            \"metadata\": {\n                \"null\": null,\n                \"array\": [\n                    1,\n                    2,\n                    3\n                ],\n                \"color\": \"gold\",\n                \"number\": 123,\n                \"object\": {\n                    \"a\": \" 串 句 龜 龜 契 金 喇\",\n                    \"c\": \"d\"\n                },\n                \"string\": \"℀ Test 豈 更 車 賈 龜 契 金 喇\",\n                \"boolean\": true\n            }\n        },\n        \"metadata\": {},\n        \"is_hardware_key_auth\": false,\n        \"is_air_gapped\": false,\n        \"device_id\": 1742895189133069,\n        \"is_borrowed\": false,\n        \"borrowed_until\": null,\n        \"is_expired\": false,\n        \"version\": \"1.0.2\",\n        \"installation_file\": \"https://s3.amazonaws.com/licensespring/SDK/Mac/ExampleMacAppV1.0.1.zip\",\n        \"release_date\": \"2021-05-09T00:00:00.000Z\",\n        \"hash_md5\": \"2eb32e05fc742061af21a199627370db\",\n        \"requires_version\": \"1.0.1\",\n        \"environment\": \"mac\",\n        \"eula_link\": \"https://docs.licensespring.com/docs/c\",\n        \"release_notes_link\": \"https://docs.licensespring.com/docs/c\",\n        \"size\": \"2734565\",\n        \"channel\": null,\n        \"license_signature\": \"KQfPkJ89kpbIs/T0xcSufU6fVzIoZMgNMuJgXG4eFsl1721aBw7ePl3kSqCQU3+8B200opR6yjdSBuqZw5OAebi/DsspG9UpMHOM38l6C/6BBHc5I1+CL5SvlLvH8/c8/fWNn4XjDd8S0VquK1+qxoukQ2N5QiwYRwHiA0y1X4n1FIYHBO+1MO+WZsdWj4SVkbiBuMWMTrVuNwmHgnSziOU/j4H3Uk5JFZqilJflAdz+jtmvciZkay8CQEKQKHnw0x8M6mWemU1dJaj0pgTeF/CXyQvTZT+9iccYPrrSEgbeeuqVexaT6qJajOjp0XNH/8Eg/eUnYZU8A2mQcZB8i2SAgVlBD9dSTCTrZP7OoJWpWJ91UtNjJ/2VWehaDXGikVF0BfQjkm+d1ZzCt3TWbWffOawxv+M+hjDWIzEkRE0qFARBCX66XT5ftZHBcuNP65vedrpkx+8ZO3jNLonEv2qChBwQcOtrnEC38kPQBkcbBxoCClbbtPp145v30mfYLXB0CudxO00j8uWWnMseg1XwMihrqWN9oDLB2obRdkiDZ/9mKSykVeUOxPTaB7T44AlgnEFki45DO6BH1ZH+cxN0shcrzXZwrpHjczNVSgIVHV4jNdyY47gH+SS/Cn6j9+jQ9IU4kZtEbFmhkTQRXS996YNsc9mFhOh2AIde/WE=\"\n    },\n    {\n        \"id\": 1742895176871049,\n        \"order_store_id\": \"0bce1a4470aa495ca53acc5b48377eb3\",\n        \"license_active\": true,\n        \"license_enabled\": true,\n        \"license_type\": \"time-limited\",\n        \"license_key\": \"UCD8-XVHJ-TSRH-W4BO\",\n        \"is_trial\": false,\n        \"max_license_users\": 1,\n        \"validity_period\": \"2045-03-25T00:00:00.000Z\",\n        \"enable_maintenance_period\": false,\n        \"maintenance_period\": null,\n        \"allow_grace_period\": false,\n        \"grace_period\": 0,\n        \"max_activations\": 1,\n        \"allow_unlimited_activations\": false,\n        \"times_activated\": 1,\n        \"start_date\": null,\n        \"transfer_count\": 0,\n        \"max_transfers\": 0,\n        \"allow_overages\": false,\n        \"max_overages\": 0,\n        \"is_floating_cloud\": false,\n        \"is_floating\": false,\n        \"floating_timeout\": 120,\n        \"can_borrow\": false,\n        \"max_borrow_time\": 0,\n        \"prevent_vm\": false,\n        \"custom_fields\": [],\n        \"product_features\": [],\n        \"customer\": {\n            \"email\": \"\",\n            \"company_name\": \"\",\n            \"reference\": \"\",\n            \"phone\": \"\",\n            \"first_name\": \"\",\n            \"last_name\": \"\",\n            \"city\": \"\",\n            \"postcode\": \"\",\n            \"state\": \"\",\n            \"country\": \"\",\n            \"address\": \"\",\n            \"customer_account\": null,\n            \"metadata\": {}\n        },\n        \"product_details\": {\n            \"product_id\": 1552912698614011,\n            \"product_name\": \"Basic product\",\n            \"short_code\": \"basicproduct\",\n            \"authorization_method\": \"license-key\",\n            \"metadata\": {}\n        },\n        \"metadata\": {},\n        \"is_hardware_key_auth\": false,\n        \"is_air_gapped\": false,\n        \"device_id\": 1742895189356079,\n        \"is_borrowed\": false,\n        \"borrowed_until\": null,\n        \"is_expired\": false,\n        \"version\": \"\",\n        \"installation_file\": \"\",\n        \"release_date\": \"\",\n        \"hash_md5\": \"\",\n        \"requires_version\": \"\",\n        \"environment\": \"\",\n        \"eula_link\": \"\",\n        \"release_notes_link\": \"\",\n        \"size\": \"\",\n        \"channel\": \"\",\n        \"license_signature\": \"G7TdP3OGP7x2IAJNoCy/nGomkQ4LhxcKVmQdPc48xgf8rO7gkg13K6aEApUyUyiRL9PGPvTEgLaaNzvmtaidpGHp/iHq2LIdqtOStc6TmGDLrNHOBwcnMbCR+YIrwXpGZA+AhjLsgjP9NJ+A1JleRv0edmHyqsuF1r6tsKYu8lUFMFHc46U2V7cCsqsZx8GeWe3LDVedLsQi6Q+A5KS3vQ8XIjz4i0zyoGYgY31CAZ6gQa6rsMeOwKOb13tHWB5n5zNk8nWbqYzt2Odb9Mi+dXgKGJNE9ez2kSSPaZnI2mC5VvVdSVPOsAxKDc3173tX6ZR2O36v3E8LBt/O9Y6IoBgs04DuuMRZko6+tqiVd6w53iB3WTMTVxWgfVgpsqjYkgcTPMTfkyNfGffpP5CwLOZ1LyBBIcqcyYWElRli9zHpdUsnkkTEJcNeERAqhg6KlNAj6tfLVOomnxPljcp08oiKeDqfSvGU0tKIXNvZInDc12dSnwyWQRN/MyNa9HY88x5Dq9QHMmG70aUM2BuvyPBPJt8t8UVj8AnwKovxPezWB9bCvGJv0l+erSDpPcQz1ll+BnBkT8+WSRPCcDC2DHAHHsCQmVO5tINdJ1u7QfndhDhtQZn5IGr4jyMuHoc2ez4E4cCJrU65XjLYbZuehFuSsPxHjP24DWZEyA7F6wk=\"\n    }\n]",
        "language": "200",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "QLX3IFr3FPKeqNnhkuAXk"
  },
  "examples": {
    "languages": [
      {
        "id": "GWm4SySjOjdn-6ywupNB1",
        "code": "curl --location --request GET '/api/v4/check_bundle?hardware_id=string&product=string&license_key=string&username=string' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string'",
        "language": "curl",
        "customLabel": ""
      },
      {
        "id": "gsTpxgOWbHiB9U8ir9jcB",
        "code": "var request = require('request');\nvar options = {\n   'method': 'GET',\n   'url': '/api/v4/check_bundle?hardware_id=string&product=string&license_key=string&username=string',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   }\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "language": "nodejs",
        "customLabel": ""
      },
      {
        "id": "J4vOm2oUIZJ9P_rQOXMEp",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar requestOptions = {\n   method: 'GET',\n   headers: myHeaders,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/check_bundle?hardware_id=string&product=string&license_key=string&username=string\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "language": "javascript",
        "customLabel": ""
      },
      {
        "id": "r5vo7idj_RXGlHTFGBL2W",
        "code": "import requests\n\nurl = \"/api/v4/check_bundle?hardware_id=string&product=string&license_key=string&username=string\"\n\npayload={}\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"GET\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "language": "python",
        "customLabel": ""
      },
      {
        "id": "Sg-mEzK0AkT-tZRhDL5k3",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/check_bundle?hardware_id=string&product=string&license_key=string&username=string\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "language": "ruby",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "J4vOm2oUIZJ9P_rQOXMEp"
  },
  "description": "Checks the status and validity of a license bundle",
  "currentNewParameter": {
    "label": "Query Parameter",
    "value": "queryParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "apiv4checkbundle",
  "legacyHash": "6TY_-XG04aw-vgfUVo06E"
}
```
:::

## Schema

### Request Query Parameters

:::CodeblockTabs
```typescript
type BundleCheckQueryParameters = ({

  // for key-based licenses:
  license_key: string

} | {

  // for user-based licenses:
  username: string

}) & {

  // required properties:
  hardware_id: string
  product: string

  // optional properties:
  license_id?: number | undefined
  is_vm?: boolean | undefined
  vm_info?: string | undefined
  os_ver?: string | undefined
  hostname?: string | undefined
  os_hostname?: string | undefined
  ip?: string | undefined
  ip_local?: string | undefined
  app_ver?: string | undefined
  sdk_ver?: string | undefined
  mac_address?: string | undefined
  include_expired_features?: boolean | undefined
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "array",
  "items": {
    "allOf": [
      {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "license_key": { "type": "string" }
            },
            "required": ["license_key"],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "username": { "type": "string" }
            },
            "required": ["username"],
            "additionalProperties": false
          }
        ]
      },
      {
        "type": "object",
        "properties": {
          "hardware_id": { "type": "string" },
          "product": { "type": "string" },
          "license_id": { "type": "number" },
          "is_vm": { "type": "boolean" },
          "vm_info": { "type": "string" },
          "os_ver": { "type": "string" },
          "hostname": { "type": "string" },
          "os_hostname": { "type": "string" },
          "ip": { "type": "string" },
          "ip_local": { "type": "string" },
          "app_ver": { "type": "string" },
          "sdk_ver": { "type": "string" },
          "mac_address": { "type": "string" },
          "include_expired_features": { "type": "boolean" }
        },
        "required": ["hardware_id", "product"],
        "additionalProperties": false
      }
    ]
  }
}
```
:::

### Response Body

:::CodeblockTabs
```typescript
type BundleCheckResponseBody = BundleCheckResponse[];

type BundleCheckResponse = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  borrowed_until: string | null,
  can_borrow: boolean,
  channel: string,
  device_id: number,
  enable_maintenance_period: boolean
  environment: string,
  eula_link: string,
  floating_timeout: number,
  grace_period: number,
  hash_md5: string,
  installation_file: string,
  is_air_gapped: boolean,
  is_borrowed: boolean,
  is_expired: boolean,
  is_floating_cloud: boolean,
  is_floating: boolean,
  is_hardware_key_auth: boolean,
  license_active: boolean,
  license_enabled: boolean,
  license_signature: string,
  license_signature_v2: string,
  offline_signature: string,
  license_type: string,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users: number,
  max_overages: number,
  max_transfers: number,
  order_store_id: string,
  prevent_vm: boolean,
  release_date: string,
  release_notes_link: string,
  requires_version: string,
  size: string,
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null, // string is in DateISO8601UTC format
  version: string,
  company: { id: number },
  
  product_features: ({
    id: number,
    code: string,
    name: string,
    expiry_date: string,
    metadata: JSON,
    feature_type: 'activation' | 'consumption',
    is_floating: boolean,
    is_floating_cloud: boolean,

    // the following properties are only present if is_floating=true or is_floating_cloud=true
    floating_users: number,
    floating_timeout: number,

    // the following properties are only present if feature_type=consumption
    max_consumption: number,
    allow_unlimited_consumptions: boolean,
    total_consumptions: number,
    allow_overages: number,
    max_overages: number,
    reset_consumption: boolean,
    consumption_period: 'daily' | 'weekly' | 'monthly' | 'annualy' | null,
    can_borrow: boolean,
    max_borrow_time: number,
  })[],
  
  custom_fields: ({
    name: string,
    data_type: 'numer' | 'text' | 'date/time',
    value: string,
  })[],
  
  customer: {
    email: string,
    company_name: string,
    reference: string,
    phone: string,
    first_name: string,
    last_name: string,
    city: string,
    postcode: string,
    state: string,
    country: string,
    address: string,
    customer_account: string | null,
    metadata: JSON,
  },
  
  product_details: {
    product_id: number,
    product_name: string,
    short_code: string,
    authorization_method: 'license-key' | 'user',
    metadata: JSON,
  },
  
  metadata: JSON,
  
  // the following property is only present if is_trial=true
  trial_days: number,
  
  // the following properties is only present if is_floating=true or is_floating_cloud=true
  floating_in_use_devices: number,
  floating_users: number,
  
  // the following properties are only present if license_type='consumption'
  max_consumptions: number,
  total_consumptions: number,
  allow_unlimited_consumptions: boolean,
  reset_consumption: boolean,
  consumption_period: string | null, // string is in DateISO8601UTC format
  
} & ({

  // for key-based licenses:
  license_key: string,

} | {

  // for user-based licenses:
  user: {
    id: number,
    email: string,
    first_name: string,
    last_name: string,
    phone_number: string,
    is_initial_password: boolean,
    max_activations: number,
    allow_unlimited_activations: boolean,
    total_activations: number
  }
});

```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "allOf": [
    {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "license_key": { "type": "string" }
          },
          "required": ["license_key"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "user": {
              "type": "object",
              "properties": {
                "id": { "type": "number" },
                "email": { "type": "string" },
                "first_name": { "type": "string" },
                "last_name": { "type": "string" },
                "phone_number": { "type": "string" },
                "is_initial_password": { "type": "boolean" },
                "max_activations": { "type": "number" },
                "allow_unlimited_activations": { "type": "boolean" },
                "total_activations": { "type": "number" }
              },
              "required": ["id", "email", "first_name", "last_name", "phone_number", "is_initial_password", "max_activations", "allow_unlimited_activations", "total_activations"],
              "additionalProperties": false
            }
          },
          "required": ["user"],
          "additionalProperties": false
        }
      ]
    },
    {
      "type": "object",
      "properties": {
        "id": { "type": "number" },
        "allow_grace_period": { "type": "boolean" },
        "allow_overages": { "type": "boolean" },
        "allow_unlimited_activations": { "type": "boolean" },
        "borrowed_until": { "type": ["string", "null"] },
        "can_borrow": { "type": "boolean" },
        "channel": { "type": "string" },
        "device_id": { "type": "number" },
        "enable_maintenance_period": { "type": "boolean" },
        "environment": { "type": "string" },
        "eula_link": { "type": "string" },
        "floating_timeout": { "type": "number" },
        "grace_period": { "type": "number" },
        "hash_md5": { "type": "string" },
        "installation_file": { "type": "string" },
        "is_air_gapped": { "type": "boolean" },
        "is_borrowed": { "type": "boolean" },
        "is_expired": { "type": "boolean" },
        "is_floating_cloud": { "type": "boolean" },
        "is_floating": { "type": "boolean" },
        "is_hardware_key_auth": { "type": "boolean" },
        "license_active": { "type": "boolean" },
        "license_enabled": { "type": "boolean" },
        "license_signature": { "type": "string" },
        "license_signature_v2": { "type": "string" },
        "offline_signature": { "type": "string" },
        "license_type": { "type": "string" },
        "maintenance_period": { "type": ["string", "null"] },
        "max_activations": { "type": "number" },
        "max_borrow_time": { "type": "number" },
        "max_license_users": { "type": "number" },
        "max_overages": { "type": "number" },
        "max_transfers": { "type": "number" },
        "order_store_id": { "type": "string" },
        "prevent_vm": { "type": "boolean" },
        "release_date": { "type": "string" },
        "release_notes_link": { "type": "string" },
        "requires_version": { "type": "string" },
        "size": { "type": "string" },
        "start_date": { "type": ["string", "null"] },
        "times_activated": { "type": "number" },
        "transfer_count": { "type": "number" },
        "validity_period": { "type": ["string", "null"] },
        "version": { "type": "string" },
        "company": { "type": "object", "properties": {"id": { "type": "number" } } },
        "product_features": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": { "type": "number" },
              "code": { "type": "string" },
              "name": { "type": "string" },
              "expiry_date": { "type": "string" },
              "metadata": {},
              "feature_type": { "type": "string", "enum": ["activation", "consumption"] },
              "is_floating": { "type": "boolean" },
              "is_floating_cloud": { "type": "boolean" },
              "floating_users": { "type": "number" },
              "floating_timeout": { "type": "number" },
              "max_consumption": { "type": "number" },
              "allow_unlimited_consumptions": { "type": "boolean" },
              "total_consumptions": { "type": "number" },
              "allow_overages": { "type": "number" },
              "max_overages": { "type": "number" },
              "max_borrow_time": { "type": "number" },
              "can_borrow": { "type": "boolean" },
              "reset_consumption": { "type": "boolean" },
              "consumption_period": {
                "type": ["string", "null"],
                "enum": ["daily", "weekly", "monthly", "annualy", null]
              }
            },
            "required": ["id", "code", "name", "expiry_date", "metadata", "feature_type", "is_floating", "is_floating_cloud"]
          }
        },
        "custom_fields": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "name": { "type": "string" },
              "data_type": { "type": "string", "enum": ["numer", "text", "date/time"] },
              "value": { "type": "string" }
            },
            "required": ["name", "data_type", "value"]
          }
        },
        "customer": {
          "type": "object",
          "properties": {
            "email": { "type": "string" },
            "company_name": { "type": "string" },
            "reference": { "type": "string" },
            "phone": { "type": "string" },
            "first_name": { "type": "string" },
            "last_name": { "type": "string" },
            "city": { "type": "string" },
            "postcode": { "type": "string" },
            "state": { "type": "string" },
            "country": { "type": "string" },
            "address": { "type": "string" },
            "customer_account": { "type": ["string", "null"] },
            "metadata": {}
          },
          "required": ["email", "company_name", "reference", "phone", "first_name", "last_name", "city", "postcode", "state", "country", "address", "metadata"]
        },
        "product_details": {
          "type": "object",
          "properties": {
            "product_id": { "type": "number" },
            "product_name": { "type": "string" },
            "short_code": { "type": "string" },
            "authorization_method": { "type": "string", "enum": ["license-key", "user"] },
            "metadata": {}
          },
          "required": ["product_id", "product_name", "short_code", "authorization_method", "metadata"]
        },
        "metadata": {},
        "trial_days": { "type": "number" },
        "floating_in_use_devices": { "type": "number" },
        "floating_users": { "type": "number" },
        "max_consumptions": { "type": "number" },
        "total_consumptions": { "type": "number" },
        "allow_unlimited_consumptions": { "type": "boolean" },
        "reset_consumption": { "type": "boolean" },
        "consumption_period": { "type": ["string", "null"] }
      },
      "required": [
        "id",
        "allow_grace_period",
        "allow_overages",
        "allow_unlimited_activations",
        "can_borrow",
        "channel",
        "device_id",
        "enable_maintenance_period",
        "environment",
        "eula_link",
        "floating_timeout",
        "grace_period",
        "hash_md5",
        "installation_file",
        "is_air_gapped",
        "is_borrowed",
        "is_expired",
        "is_floating_cloud",
        "is_floating",
        "is_hardware_key_auth",
        "license_active",
        "license_enabled",
        "license_signature",
        "license_type",
        "max_activations",
        "max_borrow_time",
        "max_license_users",
        "max_overages",
        "max_transfers",
        "order_store_id",
        "prevent_vm",
        "release_date",
        "release_notes_link",
        "requires_version",
        "size",
        "times_activated",
        "transfer_count",
        "version",
        "product_features",
        "custom_fields",
        "customer",
        "product_details",
        "metadata"
      ],
      "additionalProperties": false
    }
  ]
}
```
:::

### Response Signatures

The response objects contains the following digital signature:

- &#x20;`license_signature`: see the [**Response Signature**](docId\:ouciGcAGCAIKAdWCbx9Wk) article
- `license_signature_v2`: see the [**Response Signature v2**](docId\:VOa8G6UH1hS_qoq34lb8S) article
- `offline_signature`: can be used for activating/deactivating using the offline method, see the [**Deactivate Bundle (Offline Method)**](docId\:UCxi3f0Ly0ysvOuQHH8lF) article

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

### Key-based product licenses

Each license assigned to the product requires the client to provide a license key in order to activate, check or deactivate the license (property `license_key` in the request body).

The license response object will contain the `license_key` property, and the property `product_details.authorization_method` will be the string `license_key`.

### User-based product licenses

Each license assigned to the product has a corresponding "license user" instead of a license key. Requires `username` and to be provided.

In the license response object, `product_details.authorization_method` will have the string value `user` and the response object will contain the `user` object with information on the license user.&#x20;

## License Types

The `license_type` property defines one of the 4 types of licenses based on their duration and how the license is used:

- Perpetual: `perpetual`
- Time-limited: `time-limited`
- Subscription: `subscription`
- Consumption: `consumption`

For more information see: [**License Types**](docId\:xHxttCVj7gs6qeAqu7Cua)&#x20;

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**missing\_headers** (400): Some headers are missing
:::

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**license\_not\_found** (400): License with the provided license user not found
:::

:::BlockQuote
**license\_not\_enabled** (400): The license is not enabled
:::

:::BlockQuote
**license\_not\_active** (400): The license is not active
:::

:::BlockQuote
**device\_not\_found** (400): An active device matching the hardware\_id not found
:::

:::BlockQuote
**blacklisted** (400): This device is blacklisted
:::

:::BlockQuote
**license\_not\_enough\_consumptions** (400): Not enough consumptions left
:::

:::BlockQuote
**floating\_not\_available** (400): No available slots for floating license
:::


[title] Vendor Platform
[path] /

The vendor platform allows platform users (your staff members) to log in to their account and manage the organization's licenses. Depending on their permissions there are many tasks that can be accomplished, such as:

- Defining new products, configuring new entitlement options and license policies
- Issuing new licenses/orders
- Looking up license usage information
- Managing licenses (resetting devices/disabling licenses)
- Downloading invoices/setting up billing

:::hint{type="info"}
The vendor platform is meant for your internal users.&#x20;

For external users, please review our [**Portals**](docId\:x-e7G3fsbizUgGvYYmyVb).
:::

## Platform Dashboard

![Screenshot of the LicenseSpring Dashboard](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/a0Cta0PNiew5dME9L8i2P_image.png "Logging into LicenseSpring's Vendor account will display your dashboard.")

This section gives you a quick glance on summary aggregate statistics, as well as navigational elements to the rest of the platform.

## Other Sections of the Vendor Platform

We added separate articles to cover the functionality for the following sections of the vendor platform:

- [**Licenses**](docId:57XypajDZUSX2HPlal9yM)
- [**License Managers**](docId\:DvcMG3vUhA2p4o8BJduft)
- [**License Users**](docId\:pJlHacjMTLnAWxgMDyko2)
- [**Devices**](docId\:VADkiWjdnR8MetNJV02I6)
- [**Orders**](docId\:jl506KuN3VzHg4J99qOwQ)
- [**Customers**](docId\:bIGc1jtRtyMxhfROpZF3K)
- [**Customer Accounts**](docId\:FkcXaw797hr5BKudOaoMw)
- [**Products**](docId\:Ehq5uAHL9Jb5izdj3e8Wd)
- [**Analytics**](docId\:oIeTvYvxQege2vY_XUle3)






[title] Activate Bundle (Online Method)
[path] License API/License Activation/Deactivation/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/activate_bundle",
  "name": "/api/v4/activate_bundle",
  "method": "POST",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "String",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product bundle short code"
      },
      {
        "kind": "optional",
        "name": "license_key",
        "type": "string",
        "children": [],
        "description": "Required if product is key-based (see section below)"
      },
      {
        "kind": "optional",
        "name": "username",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "kind": "optional",
        "name": "password",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "kind": "optional",
        "name": "id_token",
        "type": "string",
        "children": [],
        "description": "Required if using SSO (see section below). This is the id_token received from the SSO if Implicit grant authorization method is being used."
      },
      {
        "kind": "optional",
        "name": "code",
        "type": "string",
        "children": [],
        "description": "Required if using SSO (see section below). This is the code received from the SSO if Authorization code grant method is being used."
      },
      {
        "kind": "optional",
        "name": "customer_account_code",
        "type": "string",
        "children": [],
        "description": "Required if using SSO (see section below). This is the customer_account_code to which SSO provider is configured. "
      },
      {
        "name": "redirect_uri",
        "kind": "optional",
        "type": "string",
        "description": "Required if using SSO with a non-default Redirect URI (see below)",
        "": "Required if using SSO with a non-default Redirect URI (see below)"
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "string",
        "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "children": []
      },
      {
        "name": "is_vm",
        "kind": "optional",
        "type": "Boolean",
        "description": "Set to true if request is sent from a Virtual Machine. If this value is true and prevent VM is set on the license, an error will be returned. If this value is set (true or false), it will be stored in license device data",
        "children": []
      },
      {
        "kind": "optional",
        "name": "vm_info",
        "type": "string",
        "children": [],
        "description": "A string describing the Virtual Machine environment which will be stored in license device data"
      },
      {
        "kind": "optional",
        "name": "os_ver",
        "type": "string",
        "children": [],
        "description": "Operating System description string which will be stored in license device data"
      },
      {
        "kind": "optional",
        "name": "hostname",
        "type": "string",
        "children": [],
        "description": "Hostname string which will be stored in license device data"
      },
      {
        "kind": "optional",
        "name": "os_hostname",
        "type": "string",
        "children": [],
        "description": "Legacy version of \"hostname\" parameter (see above)"
      },
      {
        "kind": "optional",
        "name": "ip",
        "type": "string",
        "children": [],
        "description": "Client IP address string which will be stored in license device data"
      },
      {
        "kind": "optional",
        "name": "ip_local",
        "type": "string",
        "children": [],
        "description": "Legacy version of \"ip\" parameter (see above)"
      },
      {
        "kind": "optional",
        "name": "app_ver",
        "type": "string",
        "children": [],
        "description": "Application version string which will be stored in license device data"
      },
      {
        "kind": "optional",
        "name": "sdk_ver",
        "type": "string",
        "children": [],
        "description": "SDK version string which will be stored in license device data"
      },
      {
        "kind": "optional",
        "name": "mac_address",
        "type": "string",
        "children": [],
        "description": "Client MAC address which will be stored in license device data"
      },
      {
        "name": "variables",
        "kind": "optional",
        "type": "Object",
        "description": "Stores device variables. Variables are sent as a JSON object where the key is the variable name, and the value is the value of the variable",
        "children": []
      }
    ],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "es8g1cuKJMbNPiIVt9VoF",
        "code": "[\n    {\n        \"customer\": {\n            \"email\": \"1@1.com\",\n            \"company_name\": \"\",\n            \"reference\": \"00QJ6000001ipQ1MAI\",\n            \"phone\": \"4554334\",\n            \"first_name\": \"adfasd\",\n            \"last_name\": \"fzdf\",\n            \"city\": \"\",\n            \"postcode\": \"\",\n            \"state\": \"\",\n            \"country\": \"HR\",\n            \"address\": \"\",\n            \"customer_account\": null,\n            \"metadata\": {}\n        },\n        \"custom_fields\": [],\n        \"product_features\": [],\n        \"validity_period\": null,\n        \"allow_grace_period\": false,\n        \"grace_period\": 0,\n        \"license_type\": \"perpetual\",\n        \"license_key\": \"N9WG-RY5A-Q59M-2LB2\",\n        \"is_trial\": false,\n        \"active\": false,\n        \"enable_maintenance_period\": false,\n        \"maintenance_period\": null,\n        \"max_activations\": 1,\n        \"allow_unlimited_activations\": false,\n        \"times_activated\": 1,\n        \"allow_overages\": false,\n        \"max_overages\": 0,\n        \"prevent_vm\": false,\n        \"is_floating_cloud\": false,\n        \"is_floating\": false,\n        \"floating_timeout\": 120,\n        \"transfer_count\": 0,\n        \"max_transfers\": 0,\n        \"start_date\": null,\n        \"product_details\": {\n            \"product_id\": 1586066454419525,\n            \"product_name\": \"test_bundle\",\n            \"short_code\": \"b23\",\n            \"allow_trial\": true,\n            \"trial_days\": 15,\n            \"authorization_method\": \"license-key\",\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"prevent_vm\": false,\n            \"validity_period\": null,\n            \"floating_timeout\": 120,\n            \"company_id\": 276,\n            \"metadata\": {}\n        },\n        \"can_borrow\": false,\n        \"max_borrow_time\": 0,\n        \"device_id\": 1733403637808059,\n        \"id\": 1733403616622029,\n        \"metadata\": {},\n        \"is_hardware_key_auth\": false,\n        \"is_air_gapped\": false,\n        \"license_signature\": \"raLoZyMSIuHbhum4y9L3JgBog5RwocCXvYWLtn4gt+GGxtoxed8WA57f4J1kz5PdUdZTrSs4vT5hWDiXIwDcr4tZ7fkxyH4nS55wDea61KaYsRmlDUbesgQbn1grVSL0AgfUnnxfav9AbTM0J5/UNPbw3F1ceFl26hMKv+3N67EoMSvjntyfop10BI/azbdgxr1sMF2jkPLztPFEgmrnkSEU1Vxs6ItIfxpS0u85v06jTsh6QMVBbno+lDmquW4mGFRp3+iTKwyQ8a09t8cwM2jeyYD0s4OTD861FsgZ1mt4xijD7qhTRsc8WHPP6uj+76jJ3F5zhgtM0FnSZsi90VXEVIZUP8HRl7Dgoycd5cQYMup/YpZZSgdEVmJZ9eP89FZN5KMRYHda/d3+ku0yI02jOrIx8w0EiicuOCYPf2SWaOSgh0go6HrEPQB3pfd2TY81aTfHFNMDYp/Hb0oMRy2eF5zoPUL9vwMViXUrt4l6rAuGQTg/CilklvpKrfE0U6PblDsixgVLg+YaBA1U+0uzD39sr7IDEYRKI25RpBo59k5FoxkvnEdf0rqKlLIKW35rJJiIU6Kh4mqxz5jcpHndvsr7/sQ6nnS38Aua1Xt/ePzVqftLvt+xKeHsPXFRERCISfMq3dYqy2qEGdj5muSa/6h06KJlnGwOiFcVgfw=\",\n        \"request\": \"activation\",\n        \"hardware_id\": \"hw000020\"\n    },\n    {\n        \"customer\": {\n            \"email\": \"1@1.com\",\n            \"company_name\": \"\",\n            \"reference\": \"00QJ6000001ipQ1MAI\",\n            \"phone\": \"4554334\",\n            \"first_name\": \"adfasd\",\n            \"last_name\": \"fzdf\",\n            \"city\": \"\",\n            \"postcode\": \"\",\n            \"state\": \"\",\n            \"country\": \"HR\",\n            \"address\": \"\",\n            \"customer_account\": null,\n            \"metadata\": {}\n        },\n        \"custom_fields\": [],\n        \"product_features\": [],\n        \"validity_period\": null,\n        \"allow_grace_period\": false,\n        \"grace_period\": 0,\n        \"license_type\": \"perpetual\",\n        \"license_key\": \"N9WG-RY5A-Q59M-2LB2\",\n        \"is_trial\": false,\n        \"active\": false,\n        \"enable_maintenance_period\": false,\n        \"maintenance_period\": null,\n        \"max_activations\": 1,\n        \"allow_unlimited_activations\": false,\n        \"times_activated\": 1,\n        \"allow_overages\": false,\n        \"max_overages\": 0,\n        \"prevent_vm\": false,\n        \"is_floating_cloud\": false,\n        \"is_floating\": false,\n        \"floating_timeout\": 120,\n        \"transfer_count\": 0,\n        \"max_transfers\": 0,\n        \"start_date\": null,\n        \"product_details\": {\n            \"product_id\": 1586066454419515,\n            \"product_name\": \"license-62706\",\n            \"short_code\": \"62706\",\n            \"allow_trial\": false,\n            \"trial_days\": 0,\n            \"authorization_method\": \"license-key\",\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"prevent_vm\": false,\n            \"validity_period\": null,\n            \"floating_timeout\": 120,\n            \"company_id\": 276,\n            \"metadata\": {}\n        },\n        \"can_borrow\": false,\n        \"max_borrow_time\": 0,\n        \"device_id\": 1733403638411069,\n        \"id\": 1733403616624039,\n        \"metadata\": {},\n        \"is_hardware_key_auth\": false,\n        \"is_air_gapped\": false,\n        \"license_signature\": \"raLoZyMSIuHbhum4y9L3JgBog5RwocCXvYWLtn4gt+GGxtoxed8WA57f4J1kz5PdUdZTrSs4vT5hWDiXIwDcr4tZ7fkxyH4nS55wDea61KaYsRmlDUbesgQbn1grVSL0AgfUnnxfav9AbTM0J5/UNPbw3F1ceFl26hMKv+3N67EoMSvjntyfop10BI/azbdgxr1sMF2jkPLztPFEgmrnkSEU1Vxs6ItIfxpS0u85v06jTsh6QMVBbno+lDmquW4mGFRp3+iTKwyQ8a09t8cwM2jeyYD0s4OTD861FsgZ1mt4xijD7qhTRsc8WHPP6uj+76jJ3F5zhgtM0FnSZsi90VXEVIZUP8HRl7Dgoycd5cQYMup/YpZZSgdEVmJZ9eP89FZN5KMRYHda/d3+ku0yI02jOrIx8w0EiicuOCYPf2SWaOSgh0go6HrEPQB3pfd2TY81aTfHFNMDYp/Hb0oMRy2eF5zoPUL9vwMViXUrt4l6rAuGQTg/CilklvpKrfE0U6PblDsixgVLg+YaBA1U+0uzD39sr7IDEYRKI25RpBo59k5FoxkvnEdf0rqKlLIKW35rJJiIU6Kh4mqxz5jcpHndvsr7/sQ6nnS38Aua1Xt/ePzVqftLvt+xKeHsPXFRERCISfMq3dYqy2qEGdj5muSa/6h06KJlnGwOiFcVgfw=\",\n        \"request\": \"activation\",\n        \"hardware_id\": \"hw000020\"\n    },\n    {\n        \"customer\": {\n            \"email\": \"1@1.com\",\n            \"company_name\": \"\",\n            \"reference\": \"00QJ6000001ipQ1MAI\",\n            \"phone\": \"4554334\",\n            \"first_name\": \"adfasd\",\n            \"last_name\": \"fzdf\",\n            \"city\": \"\",\n            \"postcode\": \"\",\n            \"state\": \"\",\n            \"country\": \"HR\",\n            \"address\": \"\",\n            \"customer_account\": null,\n            \"metadata\": {}\n        },\n        \"custom_fields\": [],\n        \"product_features\": [],\n        \"validity_period\": null,\n        \"allow_grace_period\": false,\n        \"grace_period\": 0,\n        \"license_type\": \"perpetual\",\n        \"license_key\": \"N9WG-RY5A-Q59M-2LB2\",\n        \"is_trial\": false,\n        \"active\": false,\n        \"enable_maintenance_period\": false,\n        \"maintenance_period\": null,\n        \"max_activations\": 1,\n        \"allow_unlimited_activations\": false,\n        \"times_activated\": 1,\n        \"allow_overages\": false,\n        \"max_overages\": 0,\n        \"prevent_vm\": false,\n        \"is_floating_cloud\": false,\n        \"is_floating\": false,\n        \"floating_timeout\": 120,\n        \"transfer_count\": 0,\n        \"max_transfers\": 0,\n        \"start_date\": null,\n        \"product_details\": {\n            \"product_id\": 1586066454419518,\n            \"product_name\": \"license-34597\",\n            \"short_code\": \"34597\",\n            \"allow_trial\": true,\n            \"trial_days\": 30,\n            \"authorization_method\": \"license-key\",\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"prevent_vm\": false,\n            \"validity_period\": null,\n            \"floating_timeout\": 120,\n            \"company_id\": 276,\n            \"metadata\": {}\n        },\n        \"can_borrow\": false,\n        \"max_borrow_time\": 0,\n        \"device_id\": 1733403638909079,\n        \"id\": 1733403616712049,\n        \"metadata\": {},\n        \"is_hardware_key_auth\": false,\n        \"is_air_gapped\": false,\n        \"license_signature\": \"raLoZyMSIuHbhum4y9L3JgBog5RwocCXvYWLtn4gt+GGxtoxed8WA57f4J1kz5PdUdZTrSs4vT5hWDiXIwDcr4tZ7fkxyH4nS55wDea61KaYsRmlDUbesgQbn1grVSL0AgfUnnxfav9AbTM0J5/UNPbw3F1ceFl26hMKv+3N67EoMSvjntyfop10BI/azbdgxr1sMF2jkPLztPFEgmrnkSEU1Vxs6ItIfxpS0u85v06jTsh6QMVBbno+lDmquW4mGFRp3+iTKwyQ8a09t8cwM2jeyYD0s4OTD861FsgZ1mt4xijD7qhTRsc8WHPP6uj+76jJ3F5zhgtM0FnSZsi90VXEVIZUP8HRl7Dgoycd5cQYMup/YpZZSgdEVmJZ9eP89FZN5KMRYHda/d3+ku0yI02jOrIx8w0EiicuOCYPf2SWaOSgh0go6HrEPQB3pfd2TY81aTfHFNMDYp/Hb0oMRy2eF5zoPUL9vwMViXUrt4l6rAuGQTg/CilklvpKrfE0U6PblDsixgVLg+YaBA1U+0uzD39sr7IDEYRKI25RpBo59k5FoxkvnEdf0rqKlLIKW35rJJiIU6Kh4mqxz5jcpHndvsr7/sQ6nnS38Aua1Xt/ePzVqftLvt+xKeHsPXFRERCISfMq3dYqy2qEGdj5muSa/6h06KJlnGwOiFcVgfw=\",\n        \"request\": \"activation\",\n        \"hardware_id\": \"hw000020\"\n    }\n]",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "7eyIlKSv2QgJcowEsDZ-2",
        "code": "{\n    \"unknown_product\": \"Provided product was not found\",\n    \"product_not_bundle\": \"Specified product \\\"productCode\\\" is not a bundle\",\n    \"license_not_found\": \"License with the provided license user not found\",\n    \"license_not_enabled\": \"The license is not enabled\",\n    \"vm_not_allowed\": \"Virtual machine not allowed\",\n    \"offline_floating_cloud_not_supported\": \" Floating cloud licenses cannot be activated offline.\",\n    \"license_start_date_error\": \"This license cannot be activated before start date: {date}\",\n    \"blacklisted\": \"This device is blacklisted\",\n    \"license_activated_max_times\": \"This license  has already been activated the maximum number of times\",\n    \"license_user_activated_max_times\": \"License user has activated this license max times\",\n    \"license_expired\": \"License validity period has expired.\",\n    \"license_transferred_max_times\": \"This license has already been transferred the maximum number of times\",\n    \"license_device_exists\": \"A device matching this hardware_id is already created on the license\"\n}",
        "language": "400",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "es8g1cuKJMbNPiIVt9VoF"
  },
  "examples": {
    "languages": [
      {
        "id": "CZWU6THnRQg1GUpNIePNI",
        "code": "curl --location --request POST '/api/v4/activate_bundle' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string' \\\n--data-raw '{\"hardware_id\":\"String\",\"product\":\"string\",\"license_key\":\"string\",\"username\":\"string\",\"password\":\"string\",\"id_token\":\"string\",\"code\":\"string\",\"customer_account_code\":\"string\",\"is_vm\":\"Boolean\",\"vm_info\":\"string\",\"os_ver\":\"string\",\"hostname\":\"string\",\"os_hostname\":\"string\",\"ip\":\"string\",\"ip_local\":\"string\",\"app_ver\":\"string\",\"sdk_ver\":\"string\",\"mac_address\":\"string\"}'",
        "language": "curl",
        "customLabel": ""
      },
      {
        "id": "iijLVaTpMZXSOO-e7JyMJ",
        "code": "var request = require('request');\nvar options = {\n   'method': 'POST',\n   'url': '/api/v4/activate_bundle',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   },\n   body: '{\"hardware_id\":\"String\",\"product\":\"string\",\"license_key\":\"string\",\"username\":\"string\",\"password\":\"string\",\"id_token\":\"string\",\"code\":\"string\",\"customer_account_code\":\"string\",\"is_vm\":\"Boolean\",\"vm_info\":\"string\",\"os_ver\":\"string\",\"hostname\":\"string\",\"os_hostname\":\"string\",\"ip\":\"string\",\"ip_local\":\"string\",\"app_ver\":\"string\",\"sdk_ver\":\"string\",\"mac_address\":\"string\"}'\n\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "language": "nodejs",
        "customLabel": ""
      },
      {
        "id": "xvxt1tUwOev1j0hw305jg",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar raw = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"password\\\":\\\"string\\\",\\\"id_token\\\":\\\"string\\\",\\\"code\\\":\\\"string\\\",\\\"customer_account_code\\\":\\\"string\\\",\\\"is_vm\\\":\\\"Boolean\\\",\\\"vm_info\\\":\\\"string\\\",\\\"os_ver\\\":\\\"string\\\",\\\"hostname\\\":\\\"string\\\",\\\"os_hostname\\\":\\\"string\\\",\\\"ip\\\":\\\"string\\\",\\\"ip_local\\\":\\\"string\\\",\\\"app_ver\\\":\\\"string\\\",\\\"sdk_ver\\\":\\\"string\\\",\\\"mac_address\\\":\\\"string\\\"}\";\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/activate_bundle\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "language": "javascript",
        "customLabel": ""
      },
      {
        "id": "q-2i3bLnzmCC8J0i7r7gV",
        "code": "import requests\n\nurl = \"/api/v4/activate_bundle\"\n\npayload = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"password\\\":\\\"string\\\",\\\"id_token\\\":\\\"string\\\",\\\"code\\\":\\\"string\\\",\\\"customer_account_code\\\":\\\"string\\\",\\\"is_vm\\\":\\\"Boolean\\\",\\\"vm_info\\\":\\\"string\\\",\\\"os_ver\\\":\\\"string\\\",\\\"hostname\\\":\\\"string\\\",\\\"os_hostname\\\":\\\"string\\\",\\\"ip\\\":\\\"string\\\",\\\"ip_local\\\":\\\"string\\\",\\\"app_ver\\\":\\\"string\\\",\\\"sdk_ver\\\":\\\"string\\\",\\\"mac_address\\\":\\\"string\\\"}\"\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "language": "python",
        "customLabel": ""
      },
      {
        "id": "08XAeN4jaCQJ--JrN1Oqd",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/activate_bundle\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\nrequest.body = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"password\\\":\\\"string\\\",\\\"id_token\\\":\\\"string\\\",\\\"code\\\":\\\"string\\\",\\\"customer_account_code\\\":\\\"string\\\",\\\"is_vm\\\":\\\"Boolean\\\",\\\"vm_info\\\":\\\"string\\\",\\\"os_ver\\\":\\\"string\\\",\\\"hostname\\\":\\\"string\\\",\\\"os_hostname\\\":\\\"string\\\",\\\"ip\\\":\\\"string\\\",\\\"ip_local\\\":\\\"string\\\",\\\"app_ver\\\":\\\"string\\\",\\\"sdk_ver\\\":\\\"string\\\",\\\"mac_address\\\":\\\"string\\\"}\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "language": "ruby",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "CZWU6THnRQg1GUpNIePNI"
  },
  "description": "Activates all licenses inside of a bundle. Returns the list of activated licenses in response\n",
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "apiv4activatebundle",
  "legacyHash": "KnONhd9BIvTJtsZQ-J6_J"
}
```
:::

## Schema

### Request Body

:::CodeblockTabs
```typescript
type BundleActivationRequestBody = ({

  // for key-based licenses:
  license_key: string

} | {

  // for user-based licenses:
  username: string
  password: string

} | {

  // for user-based licenses using single sign-on Implicit grant:
  id_token: string
  customer_account_code: string

} | {

  // for user-based licenses using single sign-on Authorization code grant:
  code: string
  customer_account_code: string

}) & {

  // required properties:
  hardware_id: string
  product: string

  // optional properties:
  bundle_code?: string | undefined
  license_id?: number | undefined
  is_vm?: boolean | undefined
  vm_info?: string | undefined
  os_ver?: string | undefined
  hostname?: string | undefined
  os_hostname?: string | undefined
  ip?: string | undefined
  ip_local?: string | undefined
  app_ver?: string | undefined
  sdk_ver?: string | undefined
  mac_address?: string | undefined
  variables?: { [key: string]: string } | undefined
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "allOf": [
    {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "license_key": { "type": "string" }
          },
          "required": ["license_key"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "username": { "type": "string" },
            "password": { "type": "string" }
          },
          "required": ["username", "password"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "id_token": { "type": "string" },
            "customer_account_code": { "type": "string" }
          },
          "required": ["id_token", "customer_account_code"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "code": { "type": "string" },
            "customer_account_code": { "type": "string" }
          },
          "required": ["code", "customer_account_code"],
          "additionalProperties": false
        }
      ]
    },
    {
      "type": "object",
      "properties": {
        "hardware_id": { "type": "string" },
        "product": { "type": "string" },
        "bundle_code": { "type": "string" },
        "license_id": { "type": "number" },
        "is_vm": { "type": "boolean" },
        "vm_info": { "type": "string" },
        "os_ver": { "type": "string" },
        "hostname": { "type": "string" },
        "os_hostname": { "type": "string" },
        "ip": { "type": "string" },
        "ip_local": { "type": "string" },
        "app_ver": { "type": "string" },
        "sdk_ver": { "type": "string" },
        "mac_address": { "type": "string" },
        "variables": {
          "type": ["object", "null"],
          "additionalProperties": { "type": "string" }
        }
      },
      "required": ["hardware_id", "product"],
      "additionalProperties": false
    }
  ]
}
```
:::

### Response Body

:::CodeblockTabs
```typescript
type BundleActivationResponseList = ({ 
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  borrowed_until: string | null,
  can_borrow: boolean,
  device_id: number,
  enable_maintenance_period: boolean
  floating_timeout: number,
  grace_period: number,
  is_air_gapped: boolean,
  is_borrowed: boolean,
  is_expired: boolean,
  is_floating_cloud: boolean,
  is_floating: boolean,
  is_hardware_key_auth: boolean,
  license_active: boolean,
  license_enabled: boolean,
  license_signature: string,
  license_type: string,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users: number,
  max_overages: number,
  max_transfers: number,
  order_store_id: string,
  prevent_vm: boolean,
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null, // string is in DateISO8601UTC format
  company: { id: number },
  installation_file_id: number | null,
  installation_file: null | {
    id: number,
    channel: string,
    environment: string,
    eula_link: string,
    hash_md5: string,
    installation_file: string,
    release_date: string | null,
    release_notes_link: string,
    requires_version: string | null,
    size: string | null,
    version: string,
  },
  
  product_features: ({
    id: number,
    code: string,
    name: string,
    expiry_date: string,
    metadata: JSON,
    feature_type: 'activation' | 'consumption',
    is_floating: boolean,
    is_floating_cloud: boolean,

    // the following properties are only present if is_floating=true or is_floating_cloud=true
    floating_users: number,
    floating_timeout: number,

    // the following properties are only present if feature_type=consumption
    max_consumption: number,
    allow_unlimited_consumptions: boolean,
    total_consumptions: number,
    allow_overages: number,
    max_overages: number,
    reset_consumption: boolean,
    consumption_period: 'daily' | 'weekly' | 'monthly' | 'annualy' | null,
    can_borrow: boolean,
    max_borrow_time: number
  })[],
  
  custom_fields: ({
    name: string,
    data_type: 'numer' | 'text' | 'date/time',
    value: string,
  })[],
  
  customer: {
    email: string,
    company_name: string,
    reference: string,
    phone: string,
    first_name: string,
    last_name: string,
    city: string,
    postcode: string,
    state: string,
    country: string,
    address: string,
    customer_account: string | null,
    metadata: JSON,
  },
  
  product_details: {
    product_id: number,
    product_name: string,
    short_code: string,
    authorization_method: 'license-key' | 'user',
    metadata: JSON,
  },
  
  metadata: JSON,
  
  // the following property is only present if is_trial=true
  trial_days: number,
  
  // the following properties is only present if is_floating=true or is_floating_cloud=true
  floating_in_use_devices: number,
  floating_users: number,
  
  // the following properties are only present if license_type='consumption'
  max_consumptions: number,
  total_consumptions: number,
  allow_unlimited_consumptions: boolean,
  reset_consumption: boolean,
  consumption_period: string | null, // string is in DateISO8601UTC format
  
} & ({

  // for key-based licenses:
  license_key: string,

} | {

  // for user-based licenses:
  user: {
    id: number,
    email: string,
    first_name: string,
    last_name: string,
    phone_number: string,
    is_initial_password: boolean,
    max_activations: number,
    allow_unlimited_activations: boolean,
    total_activations: number
  }

})[];
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "array",
  "items": {
    "type": "object",
    "allOf": [
      {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "license_key": { "type": "string" }
            },
            "required": ["license_key"],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "user": {
                "type": "object",
                "properties": {
                  "id": { "type": "number" },
                  "email": { "type": "string" },
                  "first_name": { "type": "string" },
                  "last_name": { "type": "string" },
                  "phone_number": { "type": "string" },
                  "is_initial_password": { "type": "boolean" },
                  "max_activations": { "type": "number" },
                  "allow_unlimited_activations": { "type": "boolean" },
                  "total_activations": { "type": "number" }
                },
                "required": ["id", "email", "first_name", "last_name", "phone_number", "is_initial_password", "max_activations", "allow_unlimited_activations", "total_activations"],
                "additionalProperties": false
              }
            },
            "required": ["user"],
            "additionalProperties": false
          }
        ]
      },
      {
        "type": "object",
        "properties": {
          "id": { "type": "number" },
          "allow_grace_period": { "type": "boolean" },
          "allow_overages": { "type": "boolean" },
          "allow_unlimited_activations": { "type": "boolean" },
          "borrowed_until": { "type": ["string", "null"] },
          "can_borrow": { "type": "boolean" },
          "device_id": { "type": "number" },
          "enable_maintenance_period": { "type": "boolean" },
          "floating_timeout": { "type": "number" },
          "grace_period": { "type": "number" },
          "is_air_gapped": { "type": "boolean" },
          "is_borrowed": { "type": "boolean" },
          "is_expired": { "type": "boolean" },
          "is_floating_cloud": { "type": "boolean" },
          "is_floating": { "type": "boolean" },
          "is_hardware_key_auth": { "type": "boolean" },
          "license_active": { "type": "boolean" },
          "license_enabled": { "type": "boolean" },
          "license_signature": { "type": "string" },
          "license_type": { "type": "string" },
          "maintenance_period": { "type": ["string", "null"] },
          "max_activations": { "type": "number" },
          "max_borrow_time": { "type": "number" },
          "max_license_users": { "type": "number" },
          "max_overages": { "type": "number" },
          "max_transfers": { "type": "number" },
          "order_store_id": { "type": "string" },
          "prevent_vm": { "type": "boolean" },
          "start_date": { "type": ["string", "null"] },
          "times_activated": { "type": "number" },
          "transfer_count": { "type": "number" },
          "validity_period": { "type": ["string", "null"] },
          "installation_file_id": { "type": ["number","null"] },
          "installation_file": {
            "type": "object",
            "properties": {
                "version": { "type": ["string", "null"] },
                "environment": { "type": "string" },
                "hash_md5": { "type": ["string", "null"] },
                "eula_link": { "type": ["string", "null"] },
                "release_notes_link": { "type": ["string", "null"] },
                "size": { "type": ["string", "null"] },
                "requires_version": { "type": ["string", "null"] },
                "channel": { "type": ["string", "null"] },
                "installation_file": { "type": ["string", "null"] },
                "release_date": { "type": ["string", "null"] }
            }
          },
          "company": { "type": "object", "properties": {"id": { "type": "number" } } },
          "product_features": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": { "type": "number" },
                "code": { "type": "string" },
                "name": { "type": "string" },
                "expiry_date": { "type": "string" },
                "metadata": {},
                "feature_type": { "type": "string", "enum": ["activation", "consumption"] },
                "is_floating": { "type": "boolean" },
                "is_floating_cloud": { "type": "boolean" },
                "floating_users": { "type": "number" },
                "floating_timeout": { "type": "number" },
                "max_consumption": { "type": "number" },
                "allow_unlimited_consumptions": { "type": "boolean" },
                "total_consumptions": { "type": "number" },
                "allow_overages": { "type": "number" },
                "max_overages": { "type": "number" },
                "reset_consumption": { "type": "boolean" },
                "max_borrow_time": { "type": "number" },
                "can_borrow": { "type": "boolean" },
                "consumption_period": {
                  "type": ["string", "null"],
                  "enum": ["daily", "weekly", "monthly", "annualy", null]
                }
              },
              "required": ["id", "code", "name", "expiry_date", "metadata", "feature_type", "is_floating", "is_floating_cloud"]
            }
          },
          "custom_fields": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": { "type": "string" },
                "data_type": { "type": "string", "enum": ["numer", "text", "date/time"] },
                "value": { "type": "string" }
              },
              "required": ["name", "data_type", "value"]
            }
          },
          "customer": {
            "type": "object",
            "properties": {
              "email": { "type": "string" },
              "company_name": { "type": "string" },
              "reference": { "type": "string" },
              "phone": { "type": "string" },
              "first_name": { "type": "string" },
              "last_name": { "type": "string" },
              "city": { "type": "string" },
              "postcode": { "type": "string" },
              "state": { "type": "string" },
              "country": { "type": "string" },
              "address": { "type": "string" },
              "customer_account": { "type": ["string", "null"] },
              "metadata": {}
            },
            "required": ["email", "company_name", "reference", "phone", "first_name", "last_name", "city", "postcode", "state", "country", "address", "metadata"]
          },
          "product_details": {
            "type": "object",
            "properties": {
              "product_id": { "type": "number" },
              "product_name": { "type": "string" },
              "short_code": { "type": "string" },
              "authorization_method": { "type": "string", "enum": ["license-key", "user"] },
              "metadata": {}
            },
            "required": ["product_id", "product_name", "short_code", "authorization_method", "metadata"]
          },
          "metadata": {},
          "trial_days": { "type": "number" },
          "floating_in_use_devices": { "type": "number" },
          "floating_users": { "type": "number" },
          "max_consumptions": { "type": "number" },
          "total_consumptions": { "type": "number" },
          "allow_unlimited_consumptions": { "type": "boolean" },
          "reset_consumption": { "type": "boolean" },
          "consumption_period": { "type": ["string", "null"] }
        },
        "required": [
          "id",
          "allow_grace_period",
          "allow_overages",
          "allow_unlimited_activations",
          "can_borrow",
          "channel",
          "device_id",
          "enable_maintenance_period",
          "environment",
          "eula_link",
          "floating_timeout",
          "grace_period",
          "hash_md5",
          "installation_file",
          "is_air_gapped",
          "is_borrowed",
          "is_expired",
          "is_floating_cloud",
          "is_floating",
          "is_hardware_key_auth",
          "license_active",
          "license_enabled",
          "license_signature",
          "license_type",
          "max_activations",
          "max_borrow_time",
          "max_license_users",
          "max_overages",
          "max_transfers",
          "order_store_id",
          "prevent_vm",
          "release_date",
          "release_notes_link",
          "requires_version",
          "size",
          "times_activated",
          "transfer_count",
          "version",
          "product_features",
          "custom_fields",
          "customer",
          "product_details",
          "metadata"
        ],
        "additionalProperties": false
      }
    ]
  }
}
```
:::

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

### Key-based product licenses

Each license assigned to the product requires the client to provide a license key in order to activate, check or deactivate the license (property `license_key` in the request body).

The license response object will contain the `license_key` property, and the property `product_details.authorization_method` will be the string `license_key`.

### User-based product licenses

Each license assigned to the product has a corresponding "license user" instead of a license key. There are multiple ways a user-based product license can be accessed when making a request:

- By providing the values for `username` and `password` for the license user
- By providing the values for `id_token` and `customer_account_code` if using single sign-on authentication using Implicit grant
- By providing the values for `code` and `customer_account_code` if using single sign-on authentication using Authorization code grant
-

In the license response object, `product_details.authorization_method` will have the string value `user` and the response object will contain the `user` object with information on the license user.&#x20;

## License Types

The `license_type` property defines one of the 4 types of licenses based on their duration and how the license is used:

- Perpetual: `perpetual`
- Time-limited: `time-limited`
- Subscription: `subscription`
- Consumption: `consumption`

For more information see: [**License Types**](docId\:xHxttCVj7gs6qeAqu7Cua)&#x20;

### Single-Sign-On License Activation

:::hint{type="info"}
Short instructions and link to detailed section about using Single Sign On directly via License Api can be find [**Single Sign-On URL**](docId\:QbJwnphsDcS0L25UW6PTq)&#x20;
:::

```curl
curl --location --request POST 'https://api.licensespring.com/api/v4/activate_bundle/' \
--header 'Date: Mon, 10 May 2021 13:14:18 GMT' \
--header 'Authorization: algorithm="hmac-sha256",headers="date",signature="{generated_signature}",apikey="{your_api_key}"' \
--header 'Content-Type: application/json' \
--data-raw '{
    "id_token": "{id_token_here}",
  	"code": "{code_here}",
    "customer_account_code": "acme_inc",
    "hardware_id": "some-unique-id",
    "product": "XY"
}'
```

:::hint{type="warning"}
Use either id\_token or code, not both at the same time.
:::

:::hint{type="warning"}
If you're using SSO with multiple redirect\_uri values enabled, you have to provide the `redirect_uri` in this request payload if it's the non-default uri (i.e. not the first one in the uri list)
:::

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of Exceptions

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**product\_not\_bundle** (400): Specified product "code" is not a bundle
:::

:::BlockQuote
**license\_not\_found** (400): License with the provided license user not found
:::

:::BlockQuote
**license\_not\_enabled** (400): The license is not enabled
:::

:::BlockQuote
**vm\_not\_allowed** (400): Virtual machine not allowed
:::

:::BlockQuote
**offline\_floating\_cloud\_not\_supported** (400): Floating cloud licenses cannot be activated offline
:::

:::BlockQuote
**license\_start\_date\_error&#x20;**(400): This license cannot be activated before start date: \{date}
:::

:::BlockQuote
**blacklisted** (400): This device is blacklisted
:::

:::BlockQuote
**license\_activated\_max\_times&#x20;**(400): This license key has already been activated the maximum number of times
:::

:::BlockQuote
**license\_user\_activated\_max\_times** (400): License user has activated this license max times
:::

:::BlockQuote
**license\_expired** (400): License validity period has expired
:::

:::BlockQuote
**license\_transferred\_max\_times&#x20;**(400): This license has already been transferred the maximum number of times
:::

:::BlockQuote
**license\_device\_exists&#x20;**(409): A device matching this hardware\_id is already created on the license.
:::


[title] Introduction
[path] Getting Started/

## Welcome to the LicenseSpring Documentation!

We strive to make our documentation complete, concise, up to date, and useful.&#x20;

We maintain this publicly available documentation for the benefit of our existing and prospective customers.&#x20;

## What is LicenseSpring?

LicenseSpring® is a general-purpose license manager. It primarily allows software vendors to easily control the state of their applications according to their license agreements.&#x20;

The service is offered as a SaaS in a managed service or as a single tenancy option. Some of our most popular capabilities include:

- On-premises floating license servers
- Air-gapped license activation
- Ability to license individual features within your software
- A white labeled end-user portal for your customers to manage their own licenses
- A distributor/reseller portal
- License consumptions/usage metering per component
- Analytics in aggregate or per individual licenses
- Ability to add single-sign-on as part of the license authentication process

You can watch the following videos to get an idea of everything you can do with LicenseSpring:

::embed[]{url="https://youtu.be/PTPx4EnM5Ro"}

::embed[]{url="https://www.youtube.com/watch?v=7EVFGdu91XQ"}

## Why Does LicenseSpring Exist?

### Inception:

LicenseSpring was initially developed as a homegrown License Manager, built for PDF Pro, a popular Windows-Based PDF Editor (which still uses LicenseSpring to this day!).

### Purpose

We want to Supercharge your Software! Concretely, we want to be a platform that makes life easier for all internal and external users of a software department in an organization interacting with the product.&#x20;

## What is Cense Data Inc.?

Cense Data Inc DBA LicenseSpring is the company that develops and commercializes the LicenseSpring service. The was founded in 2015 by [**Edmon Moren**](https://www.linkedin.com/in/edmonmoren/), and has offices in Vancouver, Canada.

## What is Kraken Ltd.?

Kraken Systems ltd. is the Software Engineering agency that develops and maintains the core LicenseSpring Service and Infrastructure. The company was founded by [**Dejan Strbad&#x20;**](https://www.linkedin.com/in/dstrbad/)and [**Marin Bek**](https://www.linkedin.com/in/m-bek/).  Kraken Systems ltd. is[**&#x20;ISO 27001 and ISO 9001 certified**](https://krakensystems.co/quality-and-information-security-policy), and has offices in Croatia, in the cities of Zagreb and Čakovec.&#x20;




[title] Introduction
[path] /

## Welcome to the LicenseSpring Documentation!



Our plublicly-facing documentation should


[title] License API Authorization
[path] License API/

## Overview

License API provides two methods for authorizing client requests:

- [**API Key Authorization**](docId\:LNlwU0YzLtC1FNoS9VOQj) - uses an API key and Shared key unique for each Company (vendor)
- [**OAuth Authorization**](docId\:xhYZAUaL9QY4jerxKilmk)  - uses an OAuth 2.0 system for authorization which allows for separate credentials for each Company (vendor), Customer Account, Customer or License




[title] Floating Licenses
[path] License Entitlements/

Setting up your application to accommodate floating licenses is quite simple. Due to LicenseSpring being a cloud-centric software licensing API, there's no need to set up a license server for license issuance and revocation.&#x20;

This concise guide will walk you through the process of establishing a basic floating license for your application.&#x20;

While this method offers a rapid implementation of a floating/concurrent license model, it does come with certain constraints.&#x20;

## What is a Floating License?

The primary feature of a floating license is its capacity to constrain the quantity of machines concurrently utilizing the same license.

More intricate iterations of a floating license could further confine deployment to a designated network, IP address range, or a predefined roster of machines.&#x20;

An approach to concurrent licensing, offered by LicenseSpring, involves incorporating a server-side watchdog mechanism. This watchdog periodically assesses the connection status with an application that has secured a license. In cases where the application terminates abruptly, the watchdog ensures the license is released.&#x20;

LicenseSpring has two types of floating licenses:

- [**Cloud Concurrent Licensing**](docId:4z7qU0WF3SeScJDnw76q-) where LicenseSpring is the server that manages the checking in and out of licenses.
- [**Floating License Server**](docId\:FjKmSQEK_RwFbNQRkqc5a) where licenses are issued for servers that run on-premise, and the client devices do not require an internet connection to request / release licenses from the server.

## What is License Borrowing?

A highly effective approach for extending the duration of a license beyond the default floating timeout involves license borrowing.&#x20;

With standard floating licenses, adherence to the floating timeout period is required for license validation or renewal. However, license borrowing introduces a solution wherein a license can be generated to appear as "utilized" on the floating server.&#x20;

This empowers the designated user to employ the license offline throughout the borrowing period, which can be significantly extended compared to the license's typical floating timeout. This functionality proves particularly advantageous for scenarios involving offline floating licensing.

For instance, consider a scenario where an employee must engage with a project necessitating a floating license while working remotely. Due to security constraints, accessing the license server isn't feasible. By borrowing a license for, let's say, 24 hours, the employee gains the ability to utilize the license without requiring a connection to the server during that entire 24-hour timeframe.

For information on how to setup license borrowing, see our [**Floating Licensing**](docId\:yaZxsl7FnxbYi883jYc3-) tutorial.

## What does it mean to Revoke a License?

Revoking a license refers to the forcible release (de-registration) of a floating license or floating feature from a user by an administrator with permissions to do so. This is a permission that can be granted to License Managers on the [**End-User Portal**](docId\:BOD5TlwkFFKiKasV1ZsrY), so that better control over license can be maintained by end-users. By revoking a license, you free up a license, allowing another user to register for that product. 

If you want to revoke a license and not have the same user/device re-register it then you are looking to [**Blacklist Device**](docId\:hyAfBBvWbLkEBMophTDGm) this device, not revoke the license from the device.

[title] Metadata
[path] Vendor Platform/

Metadata is a powerful feature introduced in LicenseSpring that allows you to attach custom information to various levels within your licensing infrastructure.&#x20;

It serves as a flexible and extensible mechanism for storing additional data related to licenses, features, products, and customers.&#x20;

The metadata JSON is stored as a string, providing a wide range of possibilities for customization.

## Levels of Metadata

Metadata can be applied at four different levels within LicenseSpring, providing flexibility and granularity in managing your licensing data.

### Order Metadata

Order metadata enables you to store custom information related to your orders. This level of metadata is useful for storing order-specific details.



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/bdLjadp-i0UOVhSmNche8_image.png "Metadata inside order details")

### License Metadata

License metadata allows you to attach custom information to individual licenses. This level of metadata is particularly useful for storing license-specific details that are unique to each instance.&#x20;

For example, you can add metadata to indicate the activation date, license type, or any other relevant information specific to a particular license.

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/SQEcpzYRerGUlyuE4wM4b_image.png)

### Feature Metadata

Feature metadata allows you to associate custom information with specific features within your licensing structure.&#x20;

This level of metadata can be used to store additional details about individual features, such as version numbers, release dates, or any other feature-specific data that you wish to track.

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/bGsFo3etYyYEZw04q7fyG_image.png "Metadata Location in License Feature Detail View")

### Product Metadata

Product metadata enables you to store custom information related to your products. This level of metadata is useful for storing product-specific details that are applicable to all licenses associate.&#x20;

Product metadata is returned from license check inside the `product details` object.

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/W2ZQX-ZnqiFkseGR5Ze7Y_image.png "Metadata Location in Product Detail View")

### Customer Metadata

Customer metadata allows you to attach custom information to individual customers. This level of metadata is particularly helpful for storing customer-specific details that may be important for managing your licensing relationships.&#x20;

For instance, you can add metadata to store customer preferences, contact information, or any other relevant data that pertains to a specific customer.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/BcqUPh28Sb5fYnUkp6VuH_image.png)

## Customer Accounts

Customer Accounts metadata allows you to attach custom information to group of customers. This level of metadata is particularly helpful for storing  details about group of customer accounts.&#x20;

For instance, you can add metadata to store customer accounts preferences, contact information, or any other relevant data that pertains to a specific customer accounts.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/JOaTD4lgyQ4HeVg5l6GqU_image.png)

## Working with Metadata

Managing metadata in LicenseSpring involves the adding and retrieving of metadata at the desired levels. Here's a brief overview of the basic operations for working with metadata.

### Adding Metadata:

To add metadata to a license, feature, product, or customer, you can use the appropriate API method provided by LicenseSpring.&#x20;

The `metadata` field is initially established on the product feature and, along with other fields, acts as a default value. When a license is created with specific product features, we utilize those features to generate license\_product\_feature items, inheriting default values from the product\_features, and assign them to the license.

Then, the metadata on the license product features can remain unchanged or be modified on a per-license basis, depending on your preferences. If no modifications are made, the metadata will persist in its original state.

### Retrieving Metadata

To retrieve metadata associated with a license, feature, product, or customer, you can utilize the method `metadata()` on the `License`, `LicenseFeature`, `ProductDetails`, and `Customer` classes. By providing the relevant identifier, the API will return the metadata string associated with the specified entity.

:::BlockQuote
**Note:** It's important to remember that metadata will only affect the specific entity to which it is attached and will not impact other licenses, features, products, or customers.
:::


[title] License Entitlements
[path] /

A "license entitlement" is typically used as terminology in the licensing agreement between the licensor (software vendor) and the licensee (user/customer).

In LicenseSpring, license entitlements can be configured into the licenses that you issue to your customer. The configuration options we make available to a software vendor encompass a rich set of capabilities, including start and end dates, the number of devices that can use a given license, whether a license can be transferred from one machine or customer to another, and so on.


[title] Maintenance Period
[path] License Entitlements/

Adding a maintenance period for a license gives you an additional timestamp to work with than the validity period/expiry date of the license.&#x20;

For example, if you wish to issue a license that never expires, but you wanted to charge for updates, you would set the license type to `perpetual` and just set a maintenance period expiry date.

## Add a Maintenance Period to a New or Existing License

Go to the license detail page (or "add product page" if you are issuing a new license), and check the box "enable maintenance period".&#x20;

You can select "maintenance duration" if you would like to set an end date once the license has been activated, or you can specify the end date with a calendar day.

:::hint{type="info"}
If you set a "maintenance duration" on an already activated license, the count-down will begin using the current date. If the license is not yet activated, the maintenance will will only start counting once the license has been activated.
:::



![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/QWMXyvceLjNrpQf1zNq8K_image.png "Enabling Maintenance Period")

:::hint{type="info"}
You can also add a maintenance window on a license policy, but given that the license is not being issued, LicenseSpring would not know when to set an end date, and therefore only a "maintenance duration" can be set.
:::

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/Ez9eUcAG8xaGsTTyXNcn0_image.png "Enabling Maintenance Period on License Policy")


[title] Deactivate Bundle (Offline Method)
[path] License API/License Activation/Deactivation/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/deactivate_bundle_offline",
  "name": "/api/v4/dactivate_bundle_offline",
  "method": "POST",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [
      {
        "name": "base64-encoded JSON object",
        "kind": "required",
        "type": "Object",
        "description": "The request body is a base64-encoded stringified JSON object containing the properties below. See the \"Finalized payload\" section for examples on how to generate this payload",
        "children": [
          {
            "name": "api_key OR client_id",
            "kind": "required",
            "type": "string",
            "description": "Authorization parameter used for the request, either `api_key` if using API key-based authorization, or `client_id` if using SSO authorization"
          },
          {
            "name": "date",
            "kind": "required",
            "type": "string",
            "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
          },
          {
            "name": "request_id",
            "kind": "required",
            "type": "string",
            "description": "Custom unique ID used to identify the request"
          },
          {
            "name": "request",
            "kind": "required",
            "type": "string",
            "description": "Determines the type of request: \"activation\" or \"deactivation\""
          },
          {
            "name": "signature",
            "kind": "required",
            "type": "string",
            "description": "Calculated request signature (see section below)"
          },
          {
            "name": "product",
            "kind": "required",
            "type": "string",
            "description": "Product short code"
          },
          {
            "name": "hardware_id",
            "kind": "required",
            "type": "string",
            "description": "Unique hardware ID generated for the client device"
          },
          {
            "name": "license_key",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is key-based (see section below)"
          },
          {
            "name": "username",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is user based (see section below)"
          },
          {
            "name": "license_id",
            "kind": "optional",
            "type": "Number",
            "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user"
          },
          {
            "name": "sdk_ver",
            "kind": "optional",
            "type": "string",
            "description": "SDK version string which will be logged"
          }
        ],
        "schema": [
          {
            "name": "api_key OR client_id",
            "kind": "required",
            "type": "string",
            "description": "Authorization parameter used for the request, either `api_key` if using API key-based authorization, or `client_id` if using SSO authorization"
          },
          {
            "name": "date",
            "kind": "required",
            "type": "string",
            "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
          },
          {
            "name": "request_id",
            "kind": "required",
            "type": "string",
            "description": "Custom unique ID used to identify the request"
          },
          {
            "name": "request",
            "kind": "required",
            "type": "string",
            "description": "Determines the type of request: \"activation\" or \"deactivation\""
          },
          {
            "name": "signature",
            "kind": "required",
            "type": "string",
            "description": "Calculated request signature (see section below)"
          },
          {
            "name": "product",
            "kind": "required",
            "type": "string",
            "description": "Product short code"
          },
          {
            "name": "hardware_id",
            "kind": "required",
            "type": "string",
            "description": "Unique hardware ID generated for the client device"
          },
          {
            "name": "license_key",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is key-based (see section below)"
          },
          {
            "name": "username",
            "kind": "optional",
            "type": "string",
            "description": "Required if product is user based (see section below)"
          },
          {
            "name": "license_id",
            "kind": "optional",
            "type": "Number",
            "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user"
          },
          {
            "name": "sdk_ver",
            "kind": "optional",
            "type": "string",
            "description": "SDK version string which will be logged"
          }
        ]
      }
    ],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "es8g1cuKJMbNPiIVt9VoF",
        "code": "license_deactivated",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "7eyIlKSv2QgJcowEsDZ-2",
        "code": "",
        "language": "400",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "es8g1cuKJMbNPiIVt9VoF"
  },
  "examples": {
    "languages": [
      {
        "id": "MVswmprxv53Y8L_yhrmmd",
        "language": "curl",
        "code": "curl --location --request POST '/api/v4/deactivate_bundle_offline' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string' \\\n--data-raw '_BASE64_PAYLOAD_HERE_'",
        "customLabel": ""
      },
      {
        "id": "ZCTQO7_LVyOjAVX7pP4kO",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'POST',\n   'url': '/api/v4/activate_bundle_offline',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   },\n   body: Buffer.from(JSON.stringify(offline_payload)).toString('base64')\n};\n\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "LI5XFmSVTa4QEJC9tahg2",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: btoa(JSON.stringify(offline_payload)),\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/activate_bundle_offline\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "cmQNdWH3b3clWrX7G_IxJ",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/activate_bundle_offline\"\n\npayload = \"{\\\"Payload\\\":\\\"Object\\\"}\"\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "i6V2Wf-nI00sMv9ahE5rB",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/activate_bundle_offline\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\nrequest.body = \"{\\\"Payload\\\":\\\"Object\\\"}\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "ZCTQO7_LVyOjAVX7pP4kO"
  },
  "description": "Activates all licenses inside of a bundle using the offline activation method. Returns the list of activated licenses in response\n",
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4dactivatebundleoffline",
  "legacyHash": "QO5GDP0RzYbnGkCFOCK7Y"
}
```
:::

## Schema

### Request Body

The request body is a string representing a base64-encoded JSON object containing all the required activation data.

:::hint{type="danger"}
If using "multipart/form-data" for the request, the "file" form parameter is mandatory
:::

:::CodeblockTabs
```typescript
type LicenseOfflineActivationObject = ({
  
  // for key-based licenses:
  license_key: string
  
} | {

  // for user-based licenses:
  username: string

}) & {

  // required properties:
  hardware_id: string
  product: string
  request_id: string
  signature: string
  date: string
  request: "deactivation"
  
} & ({
  api_key: string // for API key authorization
} | {
  client_id: string // for OAuth authorization
}) & {

  // optional properties:
  license_id?: number | undefined
  sdk_ver?: string | undefined
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "allOf": [
    {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "license_key": { "type": "string" }
          },
          "required": ["license_key"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "username": { "type": "string" }
          },
          "required": ["username"],
          "additionalProperties": false
        }
      ]
    },
    {
      "type": "object",
      "properties": {
        "api_key": { "type": "string" },
        "client_id": { "type": "string" },
        "request": { "type": "string" },
        "request_id": { "type": "string" },
        "date": { "type": "string" },
        "signature": { "type": "string" },
        "hardware_id": { "type": "string" },
        "product": { "type": "string" },
        "license_id": { "type": "number" },
        "sdk_ver": { "type": "string" }
      },
     "allOf": [
        { "anyOf": [{ "required": ["api_key"] }, { "required": ["client_id"] }] },
        { "anyOf": [{ "required": ["license_key"] }, { "required": ["username"] }] }
      ],
      "required": ["hardware_id", "product", "date", "signature"],
      "additionalProperties": false
    }
  ]
}
```
:::

### Signature

The `signature` value is constructed as follows:

1. The string `licenseSpring` plus a newline
2. The string `date`, plus the "date" value from the license payload object, plus a newline
3. Either the "license\_key" or "username" value from the request payload object (which ever is present on the license, see the License Authorization Method section below) plus a newline
4. The "hardware\_id" value from the request payload object plus a newline
5. The "api\_key" value from the request payload object

This complete string is then encrypted using **HMAC-SHA256** and the company **shared key** as the encryption key.

```javascript
import crypto from 'node:crypto';

const activationPayload = {
  // ...payload content...
};

// api_key or client_id depending on authorization type used:
const key = (activationPayload.api_key || activationPayload.client_id);

// if using API key authorization: the signing key is the Shared Key
// if using OAuth: the signing key is the Client Secret
const signingKey = '...';

const signingString =
  'licenseSpring\n' +
  'date: ' + activationPayload.date + '\n' +
  (activationPayload.license_key || activationPayload.username) + '\n' +
  activationPayload.hardware_id + '\n' +
  key;

  const signature = crypto
    .createHmac('sha256', signingKey)
    .update(signingString)
    .digest('base64');
```

### Finalized payload

This object is then stringified and encoded to base64, e.g.:

:::CodeblockTabs
JS Browser

```javascript
const activationPayload = {
  // ...payload content...
};
const requestBody = btoa(JSON.stringify(activationPayload));
```

nodeJS

```javascript
const activationPayload = {
  // ...payload content...
};
const requestBody = Buffer.from(JSON.stringify(activationPayload)).toString('base64');
```
:::

### Response Body

If the request succeeds, the endpoint responds with the HTTP code 200 and the string `license_deactivated`.

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

### Key-based product licenses

Each license assigned to the product requires the client to provide a license key in order to activate, check or deactivate the license (property `license_key` in the request body).

The license response object will contain the `license_key` property, and the property `product_details.authorization_method` will be the string `license_key`.

### User-based product licenses

Each license assigned to the product has a corresponding "license user" instead of a license key. Requires `username` and `password` to be provided.

In the license response object, `product_details.authorization_method` will have the string value `user` and the response object will contain the `user` object with information on the license user.&#x20;

## License Types

The `license_type` property defines one of the 4 types of licenses based on their duration and how the license is used:

- Perpetual: `perpetual`
- Time-limited: `time-limited`
- Subscription: `subscription`
- Consumption: `consumption`

For more information see: [**License Types**](docId\:xHxttCVj7gs6qeAqu7Cua)&#x20;

## Device variables

The optional `variables` parameter lets you set device variables during activation. For more information on how device variables work, see [**Device Variables**](docId\:r2cnEKm7RUFf-U0JKM0Lw)

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**missing\_headers** (400): some headers are missing
:::

- when missing authorization or date headers

:::BlockQuote
**missing\_parameters** (400): some parameters are missing in the request: different, parameters
:::

- when no request body at all or no file found in request body

:::BlockQuote
**authorization\_missing\_params** (400): some parameters are missing in authorization: different, parameters
:::

- when has request body but request body is not properly base 64 encoded
- when file is missing in request body
- when license\_key or hardware\_id body parameters are missing
- when data body parameter is missing
- when api\_key parameter is missing

:::BlockQuote
**product\_not\_bundle** (400): Specified product "\{CODE}" is not a bundle
:::

:::hint{type="info"}
If you want to use this api endpoint directly, instead of using SDK, which does most of heavy lifting for you, please contact us for additional instructions
:::

## Guide on using Offline Licenses

&#x20;If any aspect of the offline licensing model remains unclear or raises questions, we encourage you to explore our in-depth guide on [**link**](https://docs.licensespring.com/license-entitlements/activation-types/offline)

This resource offers a comprehensive explanation of the offline licensing process, how it operates, and ways to utilize its advantages for your specific software applications&#x20;


[title] 
[path] Management API/Untitled/


[title] Create Product
[path] Management API/Product/

:::ApiMethodV2
```json
{
  "name": "Creates a product if requesting manager has access permissions to it.",
  "method": "POST",
  "url": "/api/v1/products/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "P-WqHyMtfOXG1qaKG_pxB",
        "language": "json",
        "code": "{\n    \"active\": true,\n    \"product_name\": \"tmc4\",\n    \"short_code\": \"tmc4\",\n    \"default_license_type\": \"perpetual\",\n    \"subscription_duration\": \"\",\n    \"valid_duration\": \"\",\n    \"enable_maintenance_period\": false,\n    \"maintenance_duration\": \"\",\n    \"max_consumptions\": 1,\n    \"allow_overages\": false,\n    \"max_overages\": 0,\n    \"reset_consumption\": false,\n    \"consumption_period\": null,\n    \"is_floating\": false,\n    \"is_floating_cloud\": false,\n    \"floating_users\": 0,\n    \"floating_timeout\": 120,\n    \"max_activations\": 1,\n    \"allow_trial\": false,\n    \"trial_days\": 0,\n    \"authorization_method\": \"license-key\",\n    \"prevent_vm\": false,\n    \"hardware_id_required\": false,\n    \"is_upgrade\": false,\n    \"upgrade_from\": [],\n    \"is_node_locked\": true,\n    \"is_user_locked\": false\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "P-WqHyMtfOXG1qaKG_pxB"
  },
  "results": {
    "languages": [
      {
        "id": "dXgG12wbl_rliCoWV8GBa",
        "language": "200",
        "code": "{\n    \"id\": 1717144102531927,\n    \"upgrade_from\": [],\n    \"product_features\": [],\n    \"custom_fields\": [],\n    \"license_templates\": [\n        {\n            \"id\": 974,\n            \"license_product_feature_templates\": [],\n            \"license_custom_field_templates\": [],\n            \"created_at\": \"2024-05-31T08:28:22.755821Z\",\n            \"updated_at\": \"2024-05-31T08:28:22.755854Z\",\n            \"name\": \"Default license policy\",\n            \"code\": \"dftlp\",\n            \"is_default\": true,\n            \"default_license_type\": \"perpetual\",\n            \"allow_trial\": false,\n            \"trial_days\": 0,\n            \"max_activations\": 1,\n            \"allow_unlimited_activations\": false,\n            \"max_license_users\": 1,\n            \"is_floating\": false,\n            \"is_floating_cloud\": false,\n            \"floating_users\": 0,\n            \"floating_timeout\": 120,\n            \"enable_maintenance_period\": false,\n            \"maintenance_duration\": \"\",\n            \"prevent_vm\": false,\n            \"valid_duration\": \"\",\n            \"allow_grace_period\": false,\n            \"grace_period\": 0,\n            \"max_consumptions\": 1,\n            \"allow_unlimited_consumptions\": false,\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"reset_consumption\": false,\n            \"consumption_period\": null,\n            \"max_transfers\": 0,\n            \"is_air_gapped\": false,\n            \"can_borrow\": false,\n            \"max_borrow_time\": 0,\n            \"is_archived\": false,\n            \"is_hardware_key_auth\": false,\n            \"metadata\": {},\n            \"product\": 1717144102531927\n        }\n    ],\n    \"installation_files\": [],\n    \"created_at\": \"2024-05-31T08:28:23Z\",\n    \"updated_at\": \"2024-05-31T08:28:23Z\",\n    \"product_name\": \"tmc4\",\n    \"short_code\": \"tmc4\",\n    \"active\": true,\n    \"valid_duration\": \"\",\n    \"allow_trial\": false,\n    \"trial_days\": 0,\n    \"max_activations\": 1,\n    \"hardware_id_required\": false,\n    \"is_upgrade\": false,\n    \"subscription_duration\": \"\",\n    \"enable_maintenance_period\": false,\n    \"maintenance_duration\": \"\",\n    \"is_floating\": false,\n    \"is_floating_cloud\": false,\n    \"floating_users\": 0,\n    \"floating_timeout\": 120,\n    \"default_license_type\": \"perpetual\",\n    \"is_user_locked\": false,\n    \"is_node_locked\": true,\n    \"max_consumptions\": 1,\n    \"authorization_method\": \"license-key\",\n    \"prevent_vm\": false,\n    \"allow_overages\": false,\n    \"max_overages\": 0,\n    \"reset_consumption\": false,\n    \"consumption_period\": null,\n    \"is_archived\": false,\n    \"is_bundle\": false,\n    \"metadata\": {},\n    \"company\": 277\n}",
        "customLabel": ""
      },
      {
        "id": "AMOwCp3aAWH-C4WbXlt9H",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "dXgG12wbl_rliCoWV8GBa"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "product_name",
        "kind": "required",
        "type": "string",
        "description": "",
        "": "product_name"
      },
      {
        "name": "short_code",
        "kind": "required",
        "type": "string",
        "description": "only accepts alphanumeric characters, digits and dashes.",
        "": "only accepts alphanumeric characters, digits and dashes."
      },
      {
        "name": "active",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "default_license_type",
        "kind": "optional",
        "type": "string",
        "description": "values can be perpetual, subscription, time-limited, and consumption.",
        "": "values can be perpetual, subscription, time-limited, and consumption."
      },
      {
        "name": "subscription_duration",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "subscription_duration"
      },
      {
        "name": "valid_duration",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "valid_duration"
      },
      {
        "name": "enable_maintenance_period",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "maintenance_duration",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "maintenance_duration"
      },
      {
        "name": "max_consumptions",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "allow_overages",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "max_overages",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "reset_consumption ",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "consumption_period",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "consumption_period"
      },
      {
        "name": "is_floating",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "is_floating_cloud",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "floating_users",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "floating_timeout",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "max_activations",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "allow_trial",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "trial_days",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "authorization_method",
        "kind": "optional",
        "type": "string",
        "description": "values can be license-key, user.",
        "": "string"
      },
      {
        "name": "prevent_vm",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "hardware_id_required",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "is_upgrade",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "upgrade_from",
        "kind": "optional",
        "type": "string",
        "description": " list of product IDs",
        "": " list of product IDs"
      },
      {
        "name": "is_node_locked",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "is_user_locked",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "creates-a-product-if-requesting-manager-has-access",
  "legacyHash": "9LPLS0wJyUwlzLV-orQWd"
}
```
:::


[title] Error Responses
[path] License API/

The following is a list of all error responses returned by the License API.

All errors have an HTTP status of 400 of higher and the response body is a JSON object in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

| **Code** | **Status**                                           | **Notes**                                                                                                                                                   |
| -------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 404      | not\_found                                           | Requested API path doesn't exist                                                                                                                            |
| 400      | validation\_error                                    | Caused by request data not conforming to the validation schema. The `message` of the error response contains details on what failed                         |
| 400      | missing\_headers                                     | A required header is missing                                                                                                                                |
| 400      | missing\_parameters                                  | A required parameter in the query or body of the request is missing                                                                                         |
| 400      | missing\_content                                     | An offline activation/deactivation request received an empty request                                                                                        |
| 400      | invalid\_json                                        | Caused by general invalid json in POST requests                                                                                                             |
| 400      | active\_license\_required                            | A `/versions` or `/installation_file` request is called without an active license provided in the parameters                                                |
| 400      | api\_key\_product\_not\_allowed                      | An activation is being attempted using an API key which does not have permissions to activate the requested product                                         |
| 400      | archived\_product                                    | An activation is being attempted on a product which is archived                                                                                             |
| 400      | authorization\_invalid\_headers                      | Provided `Authorization` header is malformed                                                                                                                |
| 400      | authorization\_missing\_params                       | Provided `Authorization` header has missing data                                                                                                            |
| 400      | blacklisted                                          | Activation is being attempted using a blacklisted device                                                                                                    |
| 400      | borrow\_until\_not\_valid                            | `/floating/borrow` is being called with an invalid `borrowed_until` date                                                                                    |
| 400      | change\_password\_not\_allowed                       | `/change_password` is being called but is not allowed                                                                                                       |
| 400      | customer\_account\_id\_mismatch                      |                                                                                                                                                             |
| 400      | customer\_account\_not\_found                        | When creating an order, the provided `customer_account_id` does not match an existing customer                                                              |
| 400      | customer\_does\_not\_exist                           | `/customer_license_users` is being called but the provided customer does not exist                                                                          |
| 400      | customer\_not\_found                                 | `/customer_license_users` is being called with authorization values which do not grant permissions to view data for the given customer                      |
| 400      | device\_not\_found                                   | A license deactivation or an endpoint which changes license values is being called using an inactive license device                                         |
| 400      | disabled\_product                                    | A license activation is being attempted on a product which is disabled                                                                                      |
| 400      | email\_missing                                       | A request to generate a trial license for a user-based license is being attempted with no email provided                                                    |
| 400      | feature\_not\_enough\_consumptions                   | Adding a feature consumption is being attempted but the consumption limit has already been reached                                                          |
| 400      | feature\_not\_floating                               | `/floating/feature_release` is being called on a feature which is not a floating cloud feature                                                              |
| 400      | floating\_feature\_device\_not\_in\_use              | `/floating/feature_release` is being called on a feature which has no associated used device                                                                |
| 400      | floating\_not\_available                             | A check, borrow or release is being called on a floating cloud license which has no available slots left                                                    |
| 400      | hardware\_key\_required                              | An action is being attempted which requires a `licensespring-hardware-key` header                                                                           |
| 400      | hmac\_required                                       | An API-key-based Authorization header was sent but is missing a hmac value                                                                                  |
| 400      | invalid\_api\_key                                    | An invalid API key is being used                                                                                                                            |
| 400      | invalid\_hardware\_id                                | An action requiring a hardware ID parameter received an empty hardware ID                                                                                   |
| 400      | invalid\_license\_feature\_code                      | A license feature action is being attempted on a feature which cannot be found                                                                              |
| 400      | invalid\_product\_auth\_method                       | `/customer_license_users` is being called on a product which is not a user-based product                                                                    |
| 400      | invalid\_value                                       | A provided parameter does not contain a valid value. The `message` of the error will contain more information on the parameter and acceptable values        |
| 400      | key\_product\_based\_does\_not\_allow\_users         | An order is being created for a key-based license, but a list of users was provided                                                                         |
| 400      | license\_activated\_max\_times                       | A new license activation is being attempted, but the license has already been activated the maximum number of times allowed                                 |
| 400      | license\_borrow\_not\_allowed                        | A license borrowing is being attempted on a license which does not allow borrowing                                                                          |
| 400      | license\_device\_exists                              |                                                                                                                                                             |
| 400      | license\_expired                                     | A license activation or borrowing is being attempted on an expired license                                                                                  |
| 400      | license\_hwid\_not\_found                            | `/device_licenses` is being called, but the provided device has no associated licenses                                                                      |
| 400      | license\_not\_active                                 | An action is being attempted on a license which is not active                                                                                               |
| 400      | license\_not\_consumption                            | A consumption action is being attempted on a license which is not a consumption-type license                                                                |
| 400      | license\_not\_enabled                                | An action is being attempted on a license which is not enabled                                                                                              |
| 400      | license\_not\_enough\_consumptions                   | Adding a license consumption is being attempted but the consumption limit has already been reached                                                          |
| 400      | license\_not\_found                                  | An action is being attempted on a license which cannot be found                                                                                             |
| 400      | license\_start\_date\_error                          | A license activation is being attempted but is not allowed by the license's `start_date`                                                                    |
| 400      | license\_transferred\_max\_times                     | A license transfer is being attempted, but the maximum number of allowed transfers has already been reached                                                 |
| 400      | license\_user\_activated\_max\_times                 | A new license activation is being attempted, but the license user has already activated this license the maximum number of times allowed                    |
| 400      | license\_user\_not\_found                            | An action is being attempted for a user-based license, but the provided user is not associated to the license                                               |
| 400      | license\_users\_error                                | An order is being created but the number of provided users exceeds the `max_license_users` value set on the license                                         |
| 400      | missing\_hardware\_key\_certificate                  | A request requiring a `licensespring-hardware-key` was sent but the device specified has no assigned device certificate                                     |
| 400      | negative\_consumptions\_not\_allowed                 | A consumption request with a negative consumption value was sent, but negative consumptions are not allowed on this license                                 |
| 400      | oauth\_product\_not\_allowed                         | An OAuth-authorized request is being attempted using OAuth credentials which do not have access to the requested resource                                   |
| 400      | oauth\_required                                      | A request is being attempted using API Key credentials, but OAuth is enforced as the only allowed authorization mechanism                                   |
| 400      | oauth\_token\_expired                                | A request is being attempted using an expired OAuth token                                                                                                   |
| 400      | oauth\_token\_malformed                              | A request is being attempted using a malformed OAuth token                                                                                                  |
| 400      | offline\_floating\_cloud\_not\_supported             | An offline activation is being attempted on a floating cloud license which does not allow offline activation                                                |
| 400      | product\_not\_bundle                                 | A bundle action is being attempted but the specified product is not a bundle                                                                                |
| 400      | quantity\_too\_large                                 | A request for generating license keys was sent to the `/license` webhook, but the requested amount of keys to generate exceeds the maximum allowed quantity |
| 400      | read\_only\_api\_key                                 | A non-read action is being attempted using a read-only API Key                                                                                              |
| 400      | revoked\_api\_key                                    | An action is being attempted using an API Key which has been revoked                                                                                        |
| 400      | trial\_expired                                       | An activation is being attempted on an expired trial license                                                                                                |
| 400      | trial\_not\_allowed                                  | A trial license is being requested but the product does not allow trial licenses                                                                            |
| 400      | unknown\_policy\_code                                | A license policy was specified in the request but no such policy was found                                                                                  |
| 400      | unknown\_product\_code                               | A product code was specified in the request but no such product was found                                                                                   |
| 400      | unsupported\_product\_feature                        | A feature consumption is being attempted on a feature which is not a consumption feature                                                                    |
| 400      | user\_based\_product\_does\_not\_allow\_license\_key | A license in the order request contains a license key but the product is not a key-based product                                                            |
| 400      | user\_not\_assigned\_to\_product                     | A `/user_licenses` request has been sent but the provided user is not assigned to any license                                                               |
| 400      | version\_not\_found                                  | An `/installation_file` request has been sent but no file version has been found that matches the given parameters                                          |
| 400      | vm\_not\_allowed                                     | An activation is being attempted which was sent from a Virtual Machine but the licenses disallows VM activations                                            |
| 401      | authentication\_failure                              | Authentication for the request has failed                                                                                                                   |
| 401      | hardware\_key\_signature\_mismatch                   | The hardware key value sent in the `licensespring-hardware-key` is invalid                                                                                  |
| 401      | invalid\_client\_credentials                         | OAuth authentication failed                                                                                                                                 |
| 401      | offline\_signature\_mismatch                         | An offline activation or deactivation is being attempted but the provided `signature` value is invalid                                                      |
| 401      | signature\_mismatch                                  | An API-key request is being sent but the signature in the header is invalid                                                                                 |
| 409      | license\_key\_exists                                 | An order request has been sent but failed due to a `license_key` collision                                                                                  |
| 409      | order\_id\_exists                                    | A non-appending order request has been sent but the provided order `id` already exists                                                                      |
| 500      | internal\_error                                      | An unexpected server error has occured                                                                                                                      |
| 500      | adding\_manager\_error                               | An error has occured while attempting to assign a license manager                                                                                           |
| 500      | mail\_sending\_error                                 | An error has occured while attempting to send a notification for a consumption or assigning a license user to a license order                               |
| 500      | notification\_sending\_error                         | An error has occured while attempting to send a notification for a license activation, trial key, order creation                                            |


[title] List Products
[path] License API/Products/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/products",
  "name": "/api/v4/products",
  "method": "GET",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "QLX3IFr3FPKeqNnhkuAXk",
        "code": "[\n    {\n        \"created_at\": \"2023-07-15T10:23:15.000Z\",\n        \"updated_at\": \"2024-05-20T10:19:32.000Z\",\n        \"id\": 1689416595016925,\n        \"product_name\": \"abc\",\n        \"short_code\": \"def\",\n        \"active\": true,\n        \"valid_duration\": \"\",\n        \"trial_days\": 307,\n        \"max_activations\": 1,\n        \"hardware_id_required\": false,\n        \"is_upgrade\": false,\n        \"company_id\": 276,\n        \"allow_trial\": true,\n        \"enable_maintenance_period\": false,\n        \"floating_users\": 0,\n        \"is_floating\": false,\n        \"is_node_locked\": true,\n        \"is_user_locked\": false,\n        \"maintenance_duration\": \"\",\n        \"subscription_duration\": \"\",\n        \"default_license_type\": \"perpetual\",\n        \"max_consumptions\": 1,\n        \"authorization_method\": \"license-key\",\n        \"prevent_vm\": false,\n        \"allow_overages\": false,\n        \"consumption_period\": null,\n        \"max_overages\": 0,\n        \"reset_consumption\": false,\n        \"is_archived\": false,\n        \"is_floating_cloud\": false,\n        \"floating_timeout\": 120,\n        \"is_bundle\": false,\n        \"metadata\": {\n            \"a\": 1\n        },\n        \"features\": [\n            {\n                \"id\": 535,\n                \"code\": \"b\",\n                \"feature_type\": \"consumption\",\n                \"max_consumption\": 1,\n                \"metadata\": {\n                    \"a\": \"b\",\n                    \"k\": \"m\"\n                }\n            },\n            {\n                \"id\": 609,\n                \"code\": \"x\",\n                \"feature_type\": \"consumption\",\n                \"max_consumption\": 1,\n                \"metadata\": {}\n            }\n        ]\n    }\n]",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "r7pnaNGfLVC8RZ1IcgRV8",
        "code": "{\n    \"unknown_product\": \"Provided product code x was not found.\"\n    \"missing_headers\": \"must have required property 'authorization'\"\n    \"missing_parameters\": \"missing parameters\"\n  }",
        "language": "404",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "QLX3IFr3FPKeqNnhkuAXk"
  },
  "examples": {
    "languages": [
      {
        "id": "746PImYZYs67XZTCZunvc",
        "language": "curl",
        "code": "curl --location --request GET '/api/v4/products' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string'",
        "customLabel": ""
      },
      {
        "id": "k8bCiwtmATN4gT61DmQ0e",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'GET',\n   'url': '/api/v4/products',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   }\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "Oc5yC_zT4RO-cM_DaZYO_",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar requestOptions = {\n   method: 'GET',\n   headers: myHeaders,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/products\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "KK_fnENt8XuSln2IJnVBR",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/products\"\n\npayload={}\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"GET\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "6MWs64fzwnjA50ddEnOT7",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/products\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "746PImYZYs67XZTCZunvc"
  },
  "description": "Returns a list of all products",
  "currentNewParameter": {
    "label": "Query Parameter",
    "value": "queryParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4products",
  "legacyHash": "N8J7DFnfZkfw2yRXqPLW-"
}
```
:::

## Schema

### Response Body

:::CodeblockTabs
```typescript
type ListProductsResponseBody = ({
  active: boolean,
  allow_overages: boolean,
  allow_trial: boolean,
  authorization_method: 'license-key' | 'user',
  company_id: number,
  consumption_period: null,
  default_license_type: 'perpetual' | 'time-limited' | 'consumption' | 'subscription',
  enable_maintenance_period: boolean,
  floating_timeout: number,
  floating_users: number,
  hardware_id_required: boolean,
  id: number,
  is_archived: boolean,
  is_bundle: boolean,
  is_floating_cloud: boolean,
  is_floating: boolean,
  is_node_locked: boolean,
  is_upgrade: boolean,
  is_user_locked: boolean,
  maintenance_duration: string | null, // Length of time expressed in days, months or years, e.g. 5d, 2m, 3y
  max_activations: number,
  max_consumptions: number,
  max_overages: number,
  prevent_vm: boolean,
  product_name: string,
  reset_consumption: boolean,
  short_code: string,
  subscription_duration: string | null, // Length of time expressed in days, months or years, e.g. 5d, 2m, 3y
  trial_days: 0,
  valid_duration: string | null, // Date string in full ISO 8601 format, e.g. "2024-09-27T23:30:48.016Z"
  created_at: string,
  updated_at: string,
  metadata: JSON,
  features: [
    {
      id: number,
      code: string,
      feature_type: 'activation' | 'consumption',
      max_consumption: number,
      metadata: JSON
    }
  ]
})[];
```

JSON Schema

```json
```
:::

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

```json
```
:::

### List of exceptions


[title] /customer-accounts/
[path] Management API/Customer/


[title] Customer
[path] Management API/


[title] Add Feature Consumption
[path] License API/Consumption/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/add_feature_consumption",
  "name": "/api/v4/add_feature_consumption",
  "method": "POST",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "String",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "name": "feature",
        "kind": "required",
        "type": "string",
        "description": "Feature short code",
        "children": []
      },
      {
        "kind": "optional",
        "name": "license_key",
        "type": "string",
        "children": [],
        "description": "Required if product is key-based (see section below)"
      },
      {
        "kind": "optional",
        "name": "username",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "Number",
        "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "children": []
      },
      {
        "name": "consumptions",
        "kind": "optional",
        "type": "Number",
        "description": "Number of consumptions to add, defaults to 1. May be negative, unless `allow_negative_consumptions` is set to false",
        "children": []
      },
      {
        "name": "event",
        "kind": "optional",
        "type": "String",
        "description": "An optional array of strings specifying which events will be recorded in the activity log for this request. Currently can be either `consumption_add` (default) or `offline_floating_consumptions_sync` (these 2 events are mutually exclusive)",
        "children": []
      }
    ],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "es8g1cuKJMbNPiIVt9VoF",
        "code": "{\n  \"total_consumptions\": 5,\n  \"max_consumptions\": 20,\n  \"allow_unlimited_consumptions\": false,\n  \"allow_negative_consumptions\": true,\n  \"allow_overages\": false,\n  \"max_overages\": 0,\n  \"reset_consumption\": true,\n  \"consumption_period\": \"daily\",\n  \"is_floating\": false,\n  \"is_floating_cloud\": false\n}",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "7eyIlKSv2QgJcowEsDZ-2",
        "code": "{\n    \"unknown_product\": \"Provided product was not found\",\n    \"license_not_found\": \"License with the provided license user not found\",\n    \"license_not_enabled\": \"The license is not enabled\",\n    \"device_not_found\": \"An active device matching the hardware_id not found.\",\n    \"blacklisted\": \"This device is blacklisted\",\n    \"license_not_active\": \"This license is not activated\",\n    \"unsupported_product_feature\": \"One or more of requested product features     do not exists or they are not enabled on the product.\",\n    \"Feature_not_enough_consumptions\": \"Not enough consumptions left.\"",
        "language": "400",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "es8g1cuKJMbNPiIVt9VoF"
  },
  "examples": {
    "languages": [
      {
        "id": "g4vood664k7Whc9LbGSPg",
        "language": "curl",
        "code": "curl --location --request POST '/api/v4/deactivate_license' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string' \\\n--data-raw '{\"hardware_id\":\"String\",\"product\":\"string\",\"feature\":\"string\",\"license_key\":\"string\",\"username\":\"string\",\"consumptions\":\"Number\"}'",
        "customLabel": ""
      },
      {
        "id": "TrdiotUgfJeNa-IOXlHFq",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'POST',\n   'url': '/api/v4/deactivate_license',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   },\n   body: '{\"hardware_id\":\"String\",\"product\":\"string\",\"feature\":\"string\",\"license_key\":\"string\",\"username\":\"string\",\"consumptions\":\"Number\"}'\n\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "mQqeJ5439bA7y9Z3IItt5",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar raw = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"feature\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"consumptions\\\":\\\"Number\\\"}\";\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/deactivate_license\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "G-zxUMr-h-6V1LZR3bQke",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/deactivate_license\"\n\npayload = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"feature\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"consumptions\\\":\\\"Number\\\"}\"\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "NndCuKXA6Ps6tj9MKplRP",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/deactivate_license\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\nrequest.body = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"feature\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"consumptions\\\":\\\"Number\\\"}\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "G-zxUMr-h-6V1LZR3bQke"
  },
  "description": "Adds 1 or more consumptions to a license feature (only for licenses with consumption features)\n",
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4addfeatureconsumption",
  "legacyHash": "_bEEGnrgny-IozKrYYjA0"
}
```
:::

## Schema

### Request Body

:::CodeblockTabs
```typescript
type AddFeatureConsumptionRequestBody = ({
  
  // required for key-based products:
  license_key: string,
 
} | { 
  // required for user-based products:
  username: string,

}) & {
  // required parameters:
  product: string,
  hardware_id: string,
  feature: string,
  
  // optional parameters:
  license_id?: string | undefined,
  consumptions?: number | undefined,
  event?: ('consumption_add' | 'offline_floating_consumptions_sync')[] | undefined,
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "allOf": [
    {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "license_key": { "type": "string" }
          },
          "required": ["license_key"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "username": { "type": "string" }
          },
          "required": ["username"],
          "additionalProperties": false
        }
      ]
    },
    {
      "type": "object",
      "properties": {
        "hardware_id": { "type": "string" },
        "product": { "type": "string" },
        "feature": { "type": "string" },
        "license_id": { "type": "number" },
        "consumptions": { "type": "number" },
        "event": {
          "type": "array",
          "items": { "type": "string", "enum": ["consumption_add", "offline_floating_consumptions_sync"] },
          "minItems": 1,
          "not": {
            "allOf": [
              { "contains": { "const": "consumption_add" } },
              { "contains": { "const": "offline_floating_consumptions_sync" } }
            ]
          }
        }
      },
      "required": ["hardware_id", "product", "feature"],
      "additionalProperties": false
    }
  ]
}
```
:::

### Response Body

:::CodeblockTabs
```typescript
type AddFeatureConsumptionResponseBody = {
    allow_negative_consumptions: boolean,
    allow_overages: boolean,
    allow_unlimited_consumptions: boolean,
    consumption_period: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
    is_floating_cloud: boolean,
    is_floating: boolean,
    max_consumptions: number,
    max_overages: number,
    reset_consumption: boolean,
    total_consumptions: number,
    
    // the following properties are only present on floating and floating cloud features:
   floating_timeout?: number | null,
   floating_users?: number,
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": { "type": "number" },
    "max_consumptions": { "type": "number" },
    "total_consumptions": { "type": "number" },
    "allow_unlimited_consumptions": { "type": "boolean" },
    "allow_negative_consumptions": { "type": "boolean" },
    "allow_overages": { "type": "boolean" },
    "max_overages": { "type": "number" },
    "reset_consumption": { "type": "boolean" },
    "consumption_period": { "type": [ "string", "null" ], "enum": [ "daily", "weekly", "monthly", "annually", null ] },
    "is_floating_cloud": { "type": "boolean" },
    "is_floating": { "type": "boolean" },
    "floating_timeout": { "type": [ "number", null ] },
    "floating_users": { "type": "number" },
  },
  "required": [
    "id",
    "max_consumptions",
    "total_consumptions",
    "allow_unlimited_consumptions",
    "allow_negative_consumptions",
    "allow_overages",
    "max_overages",
    "reset_consumption",
    "consumption_period",
    "is_floating_cloud",
    "is_floating"
  ],
  "additionalProperties": false
}

```
:::

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

- **Key-based product licenses**: client interactions with the license have to be authorized using a `license_key`
- **User-based product licenses**: the license has a corresponding "license user" instead of a license key. Client interactions with the license have to be authorized using a `username`&#x20;

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**license\_not\_found** (400): License with the provided license user not found
:::

:::BlockQuote
**license\_not\_active** (400): The license is not active
:::

:::BlockQuote
**license\_not\_enabled** (400): The license is not enabled
:::

:::BlockQuote
**unsupported\_product\_feature** (400): One or more of requested product features do not exists or they are not enabled on the product
:::

:::BlockQuote
**feature\_not\_enough\_consumptions** (400): Not enough consumptions left
:::

:::BlockQuote
**negative\_consumptions\_not\_allowed** (400): Negative consumptions not allowed
:::

:::BlockQuote
**device\_not\_found&#x20;**(400): An active device matching the hardware\_id not found
:::

:::BlockQuote
**blacklisted** (400): This device is blacklisted
:::


[title] /customers-import-results/
[path] Management API/Customer/


[title] /product-custom-fields/
[path] Management API/Product/


[title] 
[path] Management API/Untitled/


[title] Update Customer
[path] Management API/Customer/

:::ApiMethodV2
```json
{
  "name": "Updates a customer, if requesting manager has access permissions to it.",
  "method": "PATCH",
  "url": " /api/v1/customers/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "KzyHtS8RLa32B3IdxDrtW",
        "language": "json",
        "code": "{\n    \"first_name\": \"Toni\"\n}",
        "customLabel": "Data  Examples"
      }
    ],
    "selectedLanguageId": "KzyHtS8RLa32B3IdxDrtW"
  },
  "results": {
    "languages": [
      {
        "id": "piKNqoZIOKQySBlLPxlqp",
        "language": "200",
        "code": "{\n    \"id\": 4165,\n    \"total_orders\": 0,\n    \"total_licenses\": 0,\n    \"labels\": [],\n    \"customer_account\": null,\n    \"email\": \"tc3@tc.com\",\n    \"first_name\": \"Toni\",\n    \"last_name\": \"Potter\",\n    \"company_name\": \"Hogwarts\",\n    \"phone\": \"+385913111111\",\n    \"reference\": \"ref123\",\n    \"address\": \"Street 1\",\n    \"postcode\": \"10000\",\n    \"city\": \"New York\",\n    \"country\": \"US\",\n    \"state\": \"NY\",\n    \"clabels_all\": null,\n    \"cognito_user_pool_id\": \"\",\n    \"metadata\": {},\n    \"company\": 277,\n    \"license_user\": null,\n    \"clabels\": []\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "piKNqoZIOKQySBlLPxlqp"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "email",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "email"
      },
      {
        "name": "first_name",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "first_name"
      },
      {
        "name": "last_name",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "last_name"
      },
      {
        "name": "company_name",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "company_name"
      },
      {
        "name": "phone",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "phone"
      },
      {
        "name": "reference",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "reference"
      },
      {
        "name": "address",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "address"
      },
      {
        "name": "postcode",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "postcode"
      },
      {
        "name": "city",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "city"
      },
      {
        "name": "country",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "country"
      },
      {
        "name": "state",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "state"
      },
      {
        "name": "customer_account",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "metadata",
        "kind": "optional",
        "type": "object",
        "description": "JSON Object",
        "": "JSON Object"
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "updates-a-customer-if-requesting-manager-has-acces",
  "legacyHash": "r0WNZowhZWeJZNr704vxB"
}
```
:::


[title] 
[path] Management API/Untitled/


[title] Get Client
[path] Management API/Untitled/Customer/

:::ApiMethodV2
```json
{
  "name": "Show customer OAuth client information",
  "method": "GET",
  "url": " /api/v1/customers/{id}/client",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "46MoFV-wRJCEmfXWOPaT2",
        "language": "json",
        "code": "{\n    \"id\": \"6d9103f8-aa66-4927-9680-678c42b02e2a\",\n    \"clientId\": \"auth-customer-1\",\n    \"name\": \"auth-customer-1\",\n    \"description\": \"\",\n    \"rootUrl\": \"https://api.licensespring.com\",\n    \"adminUrl\": \"https://api.licensespring.com\",\n    \"baseUrl\": \"https://api.licensespring.com\",\n    \"surrogateAuthRequired\": false,\n    \"enabled\": true,\n    \"alwaysDisplayInConsole\": false,\n    \"clientAuthenticatorType\": \"client-secret\",\n    \"secret\": \"clientsecret\",\n    \"redirectUris\": [\n        \"https://api.licensespring.com/*\"\n    ],\n    \"webOrigins\": [\n        \"+\"\n    ],\n    \"notBefore\": 0,\n    \"bearerOnly\": false,\n    \"consentRequired\": false,\n    \"standardFlowEnabled\": true,\n    \"implicitFlowEnabled\": true,\n    \"directAccessGrantsEnabled\": true,\n    \"serviceAccountsEnabled\": true,\n    \"authorizationServicesEnabled\": true,\n    \"publicClient\": false,\n    \"frontchannelLogout\": true,\n    \"protocol\": \"openid-connect\",\n    \"attributes\": {\n        \"realm_client\": \"false\",\n        \"oidc.ciba.grant.enabled\": \"false\",\n        \"client.secret.creation.time\": \"1756293587\",\n        \"backchannel.logout.session.required\": \"true\",\n        \"post.logout.redirect.uris\": \"+\",\n        \"oauth2.device.authorization.grant.enabled\": \"true\",\n        \"backchannel.logout.revoke.offline.tokens\": \"false\"\n    },\n    \"authenticationFlowBindingOverrides\": {},\n    \"fullScopeAllowed\": true,\n    \"nodeReRegistrationTimeout\": -1,\n    \"protocolMappers\": [\n        {\n            \"id\": \"96bb0d76-069c-430d-be03-3e80913d4a50\",\n            \"name\": \"Client IP Address\",\n            \"protocol\": \"openid-connect\",\n            \"protocolMapper\": \"oidc-usersessionmodel-note-mapper\",\n            \"consentRequired\": false,\n            \"config\": {\n                \"user.session.note\": \"clientAddress\",\n                \"id.token.claim\": \"true\",\n                \"introspection.token.claim\": \"true\",\n                \"access.token.claim\": \"true\",\n                \"claim.name\": \"clientAddress\",\n                \"jsonType.label\": \"String\"\n            }\n        },\n        {\n            \"id\": \"20ad3852-e836-48ad-a290-e11b464876aa\",\n            \"name\": \"Client ID\",\n            \"protocol\": \"openid-connect\",\n            \"protocolMapper\": \"oidc-usersessionmodel-note-mapper\",\n            \"consentRequired\": false,\n            \"config\": {\n                \"user.session.note\": \"client_id\",\n                \"id.token.claim\": \"true\",\n                \"introspection.token.claim\": \"true\",\n                \"access.token.claim\": \"true\",\n                \"claim.name\": \"client_id\",\n                \"jsonType.label\": \"String\"\n            }\n        },\n        {\n            \"id\": \"e398037b-9769-4fab-bea2-2432f025d8e8\",\n            \"name\": \"Client Host\",\n            \"protocol\": \"openid-connect\",\n            \"protocolMapper\": \"oidc-usersessionmodel-note-mapper\",\n            \"consentRequired\": false,\n            \"config\": {\n                \"user.session.note\": \"clientHost\",\n                \"id.token.claim\": \"true\",\n                \"introspection.token.claim\": \"true\",\n                \"access.token.claim\": \"true\",\n                \"claim.name\": \"clientHost\",\n                \"jsonType.label\": \"String\"\n            }\n        }\n    ],\n    \"defaultClientScopes\": [\n        \"web-origins\",\n        \"acr\",\n        \"roles\",\n        \"profile\",\n        \"basic\",\n        \"email\"\n    ],\n    \"optionalClientScopes\": [\n        \"address\",\n        \"phone\",\n        \"offline_access\",\n        \"microprofile-jwt\"\n    ],\n    \"access\": {\n        \"view\": true,\n        \"configure\": true,\n        \"manage\": true\n    }\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "46MoFV-wRJCEmfXWOPaT2"
  },
  "results": {
    "languages": [
      {
        "id": "tVxffThZba4Br3RmgLWO_",
        "language": "200",
        "code": "Code: 200 OK",
        "customLabel": ""
      },
      {
        "id": "Oz6jgaW-tYEV7bfCglXGQ",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "tVxffThZba4Br3RmgLWO_"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "show-customer-oauth-client-information",
  "legacyHash": "M5Q7u9ow1mBURO9MWWJSG"
}
```
:::


[title] Export Product Features
[path] Management API/Product/Features/

:::ApiMethodV2
```json
{
  "name": "Exports product features to csv if requesting manager has access permissions to them.",
  "method": "GET",
  "url": "/api/v1/product-features/export",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "cvlLPpTcM4K942-QeTg8N",
        "language": "null",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "cvlLPpTcM4K942-QeTg8N"
  },
  "results": {
    "languages": [
      {
        "id": "w4u8DmQxPOoejVGegjvlL",
        "language": "200",
        "code": "\"id\",\"created_at\",\"updated_at\",\"name\",\"code\",\"is_deleted\",\"product_id\",\"feature_type\",\"max_consumption\",\"allow_overages\",\"consumption_period\",\"max_overages\",\"reset_consumption\",\"allow_unlimited_consumptions\",\"metadata\",\"floating_timeout\",\"floating_users\",\"is_floating\",\"is_floating_cloud\",\"allow_negative_consumptions\"\n90001,\"2021-01-13 08:38:38+00:00\",\"2021-01-13 08:38:38+00:00\",\"Feature 1\",\"f1\",False,90004,\"activation\",0,False,\"\",0,False,False,\"{}\",\"\",1,False,False,True\n90002,\"2021-01-13 08:39:44+00:00\",\"2021-01-13 08:39:44+00:00\",\"Feature 2\",\"f2\",False,90004,\"consumption\",44,False,\"\",0,False,False,\"{}\",\"\",1,False,False,True\n90003,\"2021-01-13 12:29:23+00:00\",\"2021-01-13 12:29:23+00:00\",\"Feature 3\",\"f3\",False,90004,\"activation\",0,False,\"\",0,False,False,\"{}\",\"\",1,False,False,True\n90004,\"2021-01-13 13:03:31+00:00\",\"2022-12-08 07:50:25+00:00\",\"Feature 4\",\"f4\",False,90004,\"consumption\",4,False,\"\",0,False,False,\"{}\",\"\",1,False,False,True\n90005,\"2021-01-13 12:29:23+00:00\",\"2021-01-13 12:29:23+00:00\",\"Feature 5\",\"f5\",False,90004,\"activation\",0,False,\"\",0,False,False,\"{}\",120,1,False,True,True\n90006,\"2021-01-13 12:29:23+00:00\",\"2021-01-13 12:29:23+00:00\",\"Feature 6\",\"f6\",False,90009,\"activation\",0,False,\"\",0,False,False,\"{}\",120,1,False,True,True\n90007,\"2021-01-13 12:29:23+00:00\",\"2021-01-13 12:29:23+00:00\",\"Feature 7\",\"f7\",False,90009,\"activation\",0,False,\"\",0,False,False,\"{}\",120,1,False,True,True\n90008,\"2025-03-12 14:01:35.428119+00:00\",\"2025-03-12 14:01:35.428142+00:00\",\"Product A\",\"C123\",False,90001,\"activation\",0,False,\"\",0,False,False,\"{}\",\"\",1,False,False,True\n90009,\"2025-03-12 14:01:35.444040+00:00\",\"2025-03-12 14:01:35.444068+00:00\",\"Product B\",\"C456\",False,90001,\"activation\",0,False,\"\",0,False,False,\"{}\",\"\",1,False,False,True",
        "customLabel": ""
      },
      {
        "id": "ZYVntM70H2kRI4Uxg0xet",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "w4u8DmQxPOoejVGegjvlL"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "exports-product-features-to-csv-if-requesting-mana",
  "legacyHash": "ONbIk9nqO1bYJxJ1mqUIl"
}
```
:::


[title] Import Products From CSV
[path] Management API/Product/

:::hint{type="warning"}
Ensure that all text fields in your CSV use **ASCII characters**. Non-ASCII characters (such as “ä”, “ñ”, or other special symbols) can cause import errors. To avoid issues, remove or replace these characters before uploading your file.
:::

:::ApiMethodV2
```json
{
  "name": "Imports products from CSV, if requesting manager has access permissions to it.",
  "method": "GET",
  "url": "/api/v1/products/import_from_csv/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "Md5Q426svR_gPyjtwRYdx",
        "language": "null",
        "code": "product_name,short_code\nProduct A,P001\nProduct B,P002",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "Md5Q426svR_gPyjtwRYdx"
  },
  "results": {
    "languages": [
      {
        "id": "q_CuWfa9h1xrk4iL71xDm",
        "language": "200",
        "code": "{\n    \"job_id\": 10\n}",
        "customLabel": ""
      },
      {
        "id": "SM2P7Co9RZtZMaA1DW1-v",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "q_CuWfa9h1xrk4iL71xDm"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "imports-products-from-csv-if-requesting-manager-ha",
  "legacyHash": "EpTs0PWToEL4VkBluKDnm"
}
```
:::

### Content-Type

Required `Content-Type` is `multipart/form-data` with the following single key value pair:

- Key: `file`
- Value: `{csv file from which to import}`

### Required CSV Headers

- `product_name`
- `short_code`

### Possible CSV Headers

- `product_name` – String
- `short_code` – String
- `active` – Boolean
- `valid_duration` – String
- `trial_days` – Integer
- `hardware_id_required` – Boolean
- `allow_trial` – Boolean
- authorization\_method - String
  - values can be `license-key`, `user`
- `is_archived` – Boolean
- `floating_timeout` – Integer
- `is_bundle` – Boolean

:::hint{type="info"}
`job_id` from response can be used to query the import result.
:::


[title] /clables/
[path] Management API/Customer/


[title] Licenses for Device
[path] License API/List Licenses/

:::ApiMethodV2
```json
{
  "name": "List user licenses",
  "method": "GET",
  "url": "/api/v4/device_licenses",
  "description": "Returns a list of licenses assigned to a device",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "nJooa8Sw1kofn5iPWkm0F",
        "language": "javascript",
        "code": "const headers = new Headers();\nheaders.append(\"Accept\", \"application/json\");\nheaders.append(\"Date\", \"DATE_STRING\");\nheaders.append(\"Authorization\", \"AUTHORIZATION_STRING\");\n\nconst requestOptions = {\n  method: 'GET',\n  headers: headers,\n  redirect: 'follow'\n};\n\nconst queryParams = new URLSearchParams({\n  product: 'PRODUCT_STRING',\n  username: 'USERNAME_STRING',\n  password: 'PASSWORD_STRING',\n})\n.toString();\n\nfetch(\"/api/v4/user_licenses?\" + queryParams, requestOptions)\n  .then(response => response.text())\n  .then(result => console.log(result))\n  .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "wsr6xyQvbNW2pHl9kw0C7",
        "language": "curl",
        "code": "curl --location --request GET '/api/v4/device_licenses?hardware_id=STRING' \\\n--header 'Accept: application/json' \\\n--header 'Date: DATE_STRING' \\\n--header 'Authorization: AUTHORIZATION_STRING'\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "wsr6xyQvbNW2pHl9kw0C7"
  },
  "results": {
    "languages": [
      {
        "id": "1JLWp1hW3a0_JxHZ6U2-d",
        "language": "200",
        "code": "[\n    {\n        \"id\": 1702983098133459,\n        \"order_store_id\": \"trial_1702983098133439\",\n        \"license_active\": true,\n        \"license_enabled\": true,\n        \"license_type\": \"subscription\",\n        \"license_key\": \"H62K-C35N-BS2J-VZ13\",\n        \"is_trial\": true,\n        \"max_license_users\": 1,\n        \"validity_period\": \"2023-12-20\",\n        \"enable_maintenance_period\": false,\n        \"maintenance_period\": null,\n        \"allow_grace_period\": false,\n        \"grace_period\": 0,\n        \"max_activations\": 1,\n        \"allow_unlimited_activations\": true,\n        \"times_activated\": 1,\n        \"start_date\": null,\n        \"transfer_count\": 1,\n        \"max_transfers\": 0,\n        \"allow_overages\": false,\n        \"max_overages\": 0,\n        \"is_floating_cloud\": true,\n        \"is_floating\": false,\n        \"floating_timeout\": 120,\n        \"floating_in_use_devices\": 0,\n        \"can_borrow\": false,\n        \"max_borrow_time\": 0,\n        \"prevent_vm\": false,\n        \"custom_fields\": [],\n        \"product_features\": [\n            {\n                \"id\": 1702983421931584,\n                \"code\": \"e\",\n                \"name\": \"e\",\n                \"feature_type\": \"activation\",\n                \"expiry_date\": null,\n                \"metadata\": {},\n                \"is_floating\": false,\n                \"is_floating_cloud\": false\n            }\n        ],\n        \"customer\": {\n            \"email\": \"trial_request\",\n            \"company_name\": null,\n            \"reference\": \"\",\n            \"phone\": \"\",\n            \"first_name\": null,\n            \"last_name\": null,\n            \"city\": \"\",\n            \"postcode\": \"\",\n            \"state\": \"\",\n            \"country\": \"\",\n            \"address\": \"\",\n            \"customer_account\": null,\n            \"metadata\": {}\n        },\n        \"product_details\": {\n            \"product_id\": 1584723961091040,\n            \"product_name\": \"product1\",\n            \"short_code\": \"1337\",\n            \"authorization_method\": \"license-key\",\n            \"metadata\": {}\n        },\n        \"metadata\": {},\n        \"is_hardware_key_auth\": false,\n        \"is_air_gapped\": false,\n        \"floating_users\": 1,\n        \"trial_days\": 1\n    },\n    {\n        \"id\": 1700060342999659,\n        \"order_store_id\": \"trial_1700060342999639\",\n        \"license_active\": false,\n        \"license_enabled\": true,\n        \"license_type\": \"subscription\",\n        \"license_key\": \"H57Y-PS8L-VX6J-WU13\",\n        \"is_trial\": true,\n        \"max_license_users\": 1,\n        \"validity_period\": null,\n        \"enable_maintenance_period\": false,\n        \"maintenance_period\": null,\n        \"allow_grace_period\": false,\n        \"grace_period\": 0,\n        \"max_activations\": 1,\n        \"allow_unlimited_activations\": false,\n        \"times_activated\": 0,\n        \"start_date\": null,\n        \"transfer_count\": 0,\n        \"max_transfers\": 0,\n        \"allow_overages\": false,\n        \"max_overages\": 0,\n        \"is_floating_cloud\": true,\n        \"is_floating\": false,\n        \"floating_timeout\": 120,\n        \"can_borrow\": false,\n        \"max_borrow_time\": 0,\n        \"prevent_vm\": false,\n        \"custom_fields\": [],\n        \"product_features\": [\n            {\n                \"id\": 1700060342999669,\n                \"code\": \"ccc\",\n                \"name\": \"ccc\",\n                \"feature_type\": \"activation\",\n                \"expiry_date\": null,\n                \"metadata\": {},\n                \"is_floating\": false,\n                \"is_floating_cloud\": true,\n                \"floating_timeout\": 120,\n                \"floating_users\": 1\n            }\n        ],\n        \"customer\": {\n            \"email\": \"trial_request\",\n            \"company_name\": null,\n            \"reference\": \"\",\n            \"phone\": \"\",\n            \"first_name\": null,\n            \"last_name\": null,\n            \"city\": \"\",\n            \"postcode\": \"\",\n            \"state\": \"\",\n            \"country\": \"\",\n            \"address\": \"\",\n            \"customer_account\": null,\n            \"metadata\": {}\n        },\n        \"product_details\": {\n            \"product_id\": 1584723961091040,\n            \"product_name\": \"product1\",\n            \"short_code\": \"1337\",\n            \"authorization_method\": \"license-key\",\n            \"metadata\": {}\n        },\n        \"metadata\": {},\n        \"is_hardware_key_auth\": false,\n        \"is_air_gapped\": false,\n        \"floating_users\": 1,\n        \"trial_days\": 1\n    }\n]",
        "customLabel": ""
      },
      {
        "id": "0UjeUVgaV19IFSSAKOzvK",
        "language": "400",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "1JLWp1hW3a0_JxHZ6U2-d"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [
      {
        "name": "hardware_id",
        "kind": "required",
        "type": "string",
        "description": "Unique hardware ID generated for the client device",
        "children": []
      }
    ],
    "headerParameters": [
      {
        "name": "Date",
        "kind": "required",
        "type": "string",
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT",
        "children": []
      },
      {
        "name": "Authorization",
        "kind": "required",
        "type": "string",
        "description": "See \"License API Authorization\" article",
        "children": []
      }
    ],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Query Parameter",
    "value": "queryParameters"
  },
  "autoGeneratedAnchorSlug": "list-user-licenses",
  "legacyHash": "nl6z4wiomXynAO7Vx-TtV"
}
```
:::

## Schema

### Request Query Parameters

:::CodeblockTabs
```typescript
type LicensesForDeviceRequestParameters = {
  hardware_id: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "hardware_id": { "type": "string" }
  },
  "required": ["hardware_id"],
  "additionalProperties": false
}
```
:::

### Response Body

:::CodeblockTabs
```typescript
type LicensesForDeviceResponseBody = type LicenseListResponseBody = ({
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  borrowed_until: string | null, // in ISO 8601 format (always in UTC timezone), e.g. 2024-09-27T23:30:48.016Z or 2024-09-27 23:30
  can_borrow: boolean,
  channel: string,
  device_id: number,
  enable_maintenance_period: boolean
  environment: string,
  eula_link: string,
  floating_timeout: number,
  grace_period: number,
  hash_md5: string,
  installation_file: string,
  is_air_gapped: boolean,
  is_borrowed: boolean,
  is_expired: boolean,
  is_floating_cloud: boolean,
  is_floating: boolean,
  is_hardware_key_auth: boolean,
  license_active: boolean,
  license_enabled: boolean,
  license_signature: string,
  license_signature_v2: string,
  offline_signature: string,
  license_type: string,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users: number,
  max_overages: number,
  max_transfers: number,
  order_store_id: string,
  prevent_vm: boolean,
  release_date: string,
  release_notes_link: string,
  requires_version: string,
  size: string,
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null, // string is in DateISO8601UTC format
  version: string,
  company: { id: number },
  
  product_features: ({
    id: number,
    code: string,
    name: string,
    expiry_date: string,
    metadata: JSON,
    feature_type: 'activation' | 'consumption',
    is_floating: boolean,
    is_floating_cloud: boolean,

    // the following properties are only present if is_floating=true or is_floating_cloud=true
    floating_users: number,
    floating_timeout: number,

    // the following properties are only present if feature_type=consumption
    max_consumption: number,
    allow_unlimited_consumptions: boolean,
    total_consumptions: number,
    allow_overages: number,
    max_overages: number,
    reset_consumption: boolean,
    consumption_period: 'daily' | 'weekly' | 'monthly' | 'annualy' | null,
  })[],
  
  custom_fields: ({
    name: string,
    data_type: 'numer' | 'text' | 'date/time',
    value: string,
  })[],
  
  customer: {
    email: string,
    company_name: string,
    reference: string,
    phone: string,
    first_name: string,
    last_name: string,
    city: string,
    postcode: string,
    state: string,
    country: string,
    address: string,
    customer_account: string | null,
    metadata: JSON,
  },
  
  product_details: {
    product_id: number,
    product_name: string,
    short_code: string,
    authorization_method: 'license-key' | 'user',
    metadata: JSON,
  },
  
  metadata: JSON,
  
  // the following property is only present if is_trial=true
  trial_days: number,
  
  // the following properties is only present if is_floating=true or is_floating_cloud=true
  floating_in_use_devices: number,
  floating_users: number,
  
  // the following properties are only present if license_type='consumption'
  max_consumptions: number,
  total_consumptions: number,
  allow_unlimited_consumptions: boolean,
  reset_consumption: boolean,
  consumption_period: string | null, // string is in DateISO8601UTC format
  
} & ({

  // for key-based licenses:
  license_key: string,

} | {

  // for user-based licenses:
  user: {
    id: number,
    email: string,
    first_name: string,
    last_name: string,
    phone_number: string,
    is_initial_password: boolean,
    max_activations: number,
    allow_unlimited_activations: boolean,
    total_activations: number
  }
}))[];
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "array",
  "items": {
    "type": "object",
    "allOf": [
      {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "license_key": { "type": "string" }
            },
            "required": ["license_key"],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "user": {
                "type": "object",
                "properties": {
                  "id": { "type": "number" },
                  "email": { "type": "string" },
                  "first_name": { "type": "string" },
                  "last_name": { "type": "string" },
                  "phone_number": { "type": "string" },
                  "is_initial_password": { "type": "boolean" },
                  "max_activations": { "type": "number" },
                  "allow_unlimited_activations": { "type": "boolean" },
                  "total_activations": { "type": "number" }
                },
                "required": ["id", "email", "first_name", "last_name", "phone_number", "is_initial_password", "max_activations", "allow_unlimited_activations", "total_activations"],
                "additionalProperties": false
              }
            },
            "required": ["user"],
            "additionalProperties": false
          }
        ]
      },
      {
        "type": "object",
        "properties": {
          "id": { "type": "number" },
          "allow_grace_period": { "type": "boolean" },
          "allow_overages": { "type": "boolean" },
          "allow_unlimited_activations": { "type": "boolean" },
          "borrowed_until": { "type": ["string", "null"] },
          "can_borrow": { "type": "boolean" },
          "channel": { "type": "string" },
          "device_id": { "type": "number" },
          "enable_maintenance_period": { "type": "boolean" },
          "environment": { "type": "string" },
          "eula_link": { "type": "string" },
          "floating_timeout": { "type": "number" },
          "grace_period": { "type": "number" },
          "hash_md5": { "type": "string" },
          "installation_file": { "type": "string" },
          "is_air_gapped": { "type": "boolean" },
          "is_borrowed": { "type": "boolean" },
          "is_expired": { "type": "boolean" },
          "is_floating_cloud": { "type": "boolean" },
          "is_floating": { "type": "boolean" },
          "is_hardware_key_auth": { "type": "boolean" },
          "license_active": { "type": "boolean" },
          "license_enabled": { "type": "boolean" },
          "license_signature": { "type": "string" },
          "license_signature_v2": { "type": "string" },
          "offline_signature": { "type": "string" },
          "license_type": { "type": "string" },
          "maintenance_period": { "type": ["string", "null"] },
          "max_activations": { "type": "number" },
          "max_borrow_time": { "type": "number" },
          "max_license_users": { "type": "number" },
          "max_overages": { "type": "number" },
          "max_transfers": { "type": "number" },
          "order_store_id": { "type": "string" },
          "prevent_vm": { "type": "boolean" },
          "release_date": { "type": "string" },
          "release_notes_link": { "type": "string" },
          "requires_version": { "type": "string" },
          "size": { "type": "string" },
          "start_date": { "type": ["string", "null"] },
          "times_activated": { "type": "number" },
          "transfer_count": { "type": "number" },
          "validity_period": { "type": ["string", "null"] },
          "version": { "type": "string" },
          "company": { "type": "object", "properties": {"id": { "type": "number" } } },
          "product_features": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": { "type": "number" },
                "code": { "type": "string" },
                "name": { "type": "string" },
                "expiry_date": { "type": "string" },
                "metadata": { "type": "object" },
                "feature_type": { "type": "string", "enum": ["activation", "consumption"] },
                "is_floating": { "type": "boolean" },
                "is_floating_cloud": { "type": "boolean" },
                "floating_users": { "type": "number" },
                "floating_timeout": { "type": "number" },
                "max_consumption": { "type": "number" },
                "allow_unlimited_consumptions": { "type": "boolean" },
                "total_consumptions": { "type": "number" },
                "allow_overages": { "type": "number" },
                "max_overages": { "type": "number" },
                "reset_consumption": { "type": "boolean" },
                "consumption_period": {
                  "type": ["string", "null"],
                  "enum": ["daily", "weekly", "monthly", "annualy", null]
                }
              },
              "required": ["id", "code", "name", "expiry_date", "metadata", "feature_type", "is_floating", "is_floating_cloud"]
            }
          },
          "custom_fields": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": { "type": "string" },
                "data_type": { "type": "string", "enum": ["numer", "text", "date/time"] },
                "value": { "type": "string" }
              },
              "required": ["name", "data_type", "value"]
            }
          },
          "customer": {
            "type": "object",
            "properties": {
              "email": { "type": "string" },
              "company_name": { "type": "string" },
              "reference": { "type": "string" },
              "phone": { "type": "string" },
              "first_name": { "type": "string" },
              "last_name": { "type": "string" },
              "city": { "type": "string" },
              "postcode": { "type": "string" },
              "state": { "type": "string" },
              "country": { "type": "string" },
              "address": { "type": "string" },
              "customer_account": { "type": ["string", "null"] },
              "metadata": { "type": "object" }
            },
            "required": ["email", "company_name", "reference", "phone", "first_name", "last_name", "city", "postcode", "state", "country", "address", "metadata"]
          },
          "product_details": {
            "type": "object",
            "properties": {
              "product_id": { "type": "number" },
              "product_name": { "type": "string" },
              "short_code": { "type": "string" },
              "authorization_method": { "type": "string", "enum": ["license-key", "user"] },
              "metadata": { "type": "object" }
            },
            "required": ["product_id", "product_name", "short_code", "authorization_method", "metadata"]
          },
          "metadata": { "type": "object" },
          "trial_days": { "type": "number" },
          "floating_users": { "type": "number" },
          "floating_in_use_devices": { "type": "number" },
          "max_consumptions": { "type": "number" },
          "total_consumptions": { "type": "number" },
          "allow_unlimited_consumptions": { "type": "boolean" },
          "reset_consumption": { "type": "boolean" },
          "consumption_period": { "type": ["string", "null"] }
        },
        "required": [
          "id",
          "allow_grace_period",
          "allow_overages",
          "allow_unlimited_activations",
          "can_borrow",
          "channel",
          "device_id",
          "enable_maintenance_period",
          "environment",
          "eula_link",
          "floating_timeout",
          "grace_period",
          "hash_md5",
          "installation_file",
          "is_air_gapped",
          "is_borrowed",
          "is_expired",
          "is_floating_cloud",
          "is_floating",
          "is_hardware_key_auth",
          "license_active",
          "license_enabled",
          "license_signature",
          "license_signature_v2",
          "offline_signature",
          "license_type",
          "max_activations",
          "max_borrow_time",
          "max_license_users",
          "max_overages",
          "max_transfers",
          "order_store_id",
          "prevent_vm",
          "release_date",
          "release_notes_link",
          "requires_version",
          "size",
          "times_activated",
          "transfer_count",
          "version",
          "product_features",
          "custom_fields",
          "customer",
          "product_details",
          "metadata"
        ],
        "additionalProperties": false
      }
    ]
  }
}

```
:::

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions


[title] Track Device Variables
[path] License API/Device Variables/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/track_device_variables",
  "name": "/api/v4/track_device_variables",
  "method": "POST",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "String",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "name": "variables",
        "kind": "required",
        "type": "Object",
        "description": "JSON key-value object, with keys being variable names and values being the values to set for those variables. Values may be: string, number or boolean",
        "children": []
      },
      {
        "kind": "optional",
        "name": "license_key",
        "type": "string",
        "children": [],
        "description": "Required if product is key-based (see section below)"
      },
      {
        "kind": "optional",
        "name": "username",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "Number",
        "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "children": []
      }
    ],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "es8g1cuKJMbNPiIVt9VoF",
        "code": "[\n    {\n        \"variable\": \"first_variable\",\n        \"value\": \"cooling\",\n        \"device_id\": 1698663677416479,\n        \"created_at\": 1698667364802\n    }\n]",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "7eyIlKSv2QgJcowEsDZ-2",
        "code": "{\n    \"unknown_product\": \"Provided product was not found\",\n    \"license_not_found\": \"License with the provided license user not found\",\n    \"license_not_enabled\": \"The license is not enabled\",\n    \"blacklisted\": \"This device is blacklisted\",\n    \"device_not_found\": \"An active device matching the hardware_id not found.\",\n}\n    ",
        "language": "400",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "es8g1cuKJMbNPiIVt9VoF"
  },
  "examples": {
    "languages": [
      {
        "id": "SjeyS-1XundNPNhVQaonK",
        "language": "curl",
        "code": "curl --location --request POST '/api/v4/track_device_variables' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string' \\\n--data-raw '{\"hardware_id\":\"String\",\"product\":\"string\",\"variables\":\"Object\",\"license_key\":\"string\",\"username\":\"string\"}'",
        "customLabel": ""
      },
      {
        "id": "ZDMwSkrxf1DcrdsRwLbEQ",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'POST',\n   'url': '/api/v4/track_device_variables',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   },\n   body: '{\"hardware_id\":\"String\",\"product\":\"string\",\"variables\":\"Object\",\"license_key\":\"string\",\"username\":\"string\"}'\n\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "gDrtIKUYhQbgAW9fIE09U",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar raw = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"variables\\\":\\\"Object\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\"}\";\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/track_device_variables\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "zTc9gvMEg5PjPmZ12biAq",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/track_device_variables\"\n\npayload = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"variables\\\":\\\"Object\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\"}\"\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "YzOjz6PHGJI3pGgn8PKjc",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/track_device_variables\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\nrequest.body = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"variables\\\":\\\"Object\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\"}\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "zTc9gvMEg5PjPmZ12biAq"
  },
  "description": "Stores metadata for a specific device\n",
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4trackdevicevariables",
  "legacyHash": "w1jbK7SlXnRWbGWH66ABH"
}
```
:::

::::hint{type="info"}
**Variables** are sent as a **JSON object**, where parameter is the variable name and value is the value of the variable, e.g.:

:::BlockQuote
"variables": \{
&#x20;   "some\_variable\_name": "some value",
&#x20;   "another\_variable\_name": "another value"
}
:::
::::

:::hint{type="danger"}
If a variable **already exists** on the device, its value will be **overwritten**
:::

:::hint{type="info"}
Device variables can also be set during activation by providing a `variables` parameter in the activation payload, with the same syntax as described on this page. For more details see: [**Activate License (Online Method)**](docId\:Mt2yGm6CJzh2bumU-Gfww), [**Deactivate Bundle (Offline Method)**](docId\:UCxi3f0Ly0ysvOuQHH8lF)&#x20;
:::

## Schema

### Request Body

:::CodeblockTabs
```typescript
type TrackDeviceVariablesRequestBody = {
  
  // required parameters:
  product: string,
  hardware_id: string,
  variables: {
    [key: string]: string | number | boolean,
  }
  
  // required for key-based products:
  license_key: string,
  
  // required for user-based products:
  username: string,
}
```

JSON Schema

```json
```
:::

### Response Body

:::CodeblockTabs
```typescript
type TrackDeviceVariablesResponseBody = ({
    variable: string,
    value: string | number | boolean,
    device_id: number,
    created_at: number, // UNIX Timestamp in milliseconds, e.g. 1737128752745
})[];
```

JSON Schema

```json
```
:::

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

- **Key-based product licenses**: client interactions with the license have to be authorized using a `license_key`
- **User-based product licenses**: the license has a corresponding "license user" instead of a license key. Client interactions with the license have to be authorized using a `username`&#x20;

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**license\_not\_found** (400): License with the provided license user not found
:::

:::BlockQuote
**license\_not\_active&#x20;**(400): The license is not active
:::

:::BlockQuote
**license\_not\_enabled** (400): The license is not enabled
:::

:::BlockQuote
**device\_not\_found** (400): An active device matching the hardware\_id not found
:::

:::BlockQuote
**blacklisted** (400): This device is blacklisted
:::


[title] List Licenses
[path] License API/


[title] Get Product Versions
[path] License API/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/versions",
  "name": "/api/v4/versions",
  "method": "GET",
  "request": {
    "pathParameters": [],
    "queryParameters": [
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "string",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "kind": "optional",
        "name": "license_key",
        "type": "string",
        "children": [],
        "description": "Required if product is key-based (see section below)"
      },
      {
        "kind": "optional",
        "name": "username",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "Number",
        "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "children": []
      },
      {
        "name": "env",
        "kind": "optional",
        "type": "string",
        "description": "Environment identifier, e.g. \"win\", \"win32\", \"win64\", \"mac\", \"linux\", \"linux32\", \"linux64\"",
        "children": []
      },
      {
        "name": "channel",
        "kind": "optional",
        "type": "string",
        "description": "Channel identifier, e.g. \"staging\", \"prod\"",
        "children": []
      }
    ],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "QLX3IFr3FPKeqNnhkuAXk",
        "code": "[\n    {\n        \"version\": \"1.0.0.\",\n        \"release_date\": \"2020-11-30T00:00:00.000Z\"\n    },\n    {\n        \"version\": \"1.0.1.\",\n        \"release_date\": \"2020-11-30T00:00:00.000Z\"\n    },\n    {\n        \"version\": \"1.0.2\",\n        \"release_date\": \"2021-04-30T00:00:00.000Z\"\n    }\n]",
        "language": "200",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "QLX3IFr3FPKeqNnhkuAXk"
  },
  "examples": {
    "languages": [
      {
        "id": "O5TXrDheiYbVU5SAC4R6e",
        "language": "curl",
        "code": "curl --location --request GET '/api/v4/versions?hardware_id=string&product=string&license_key=string&username=string' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string'",
        "customLabel": ""
      },
      {
        "id": "Tyn1OMMYHf75-2QcLvpbY",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'GET',\n   'url': '/api/v4/versions?hardware_id=string&product=string&license_key=string&username=string',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   }\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "YHcoJeJcSji84OLe_GP4Y",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar requestOptions = {\n   method: 'GET',\n   headers: myHeaders,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/versions?hardware_id=string&product=string&license_key=string&username=string\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "j79rqQ2T9reOOSPbOD1Op",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/versions?hardware_id=string&product=string&license_key=string&username=string\"\n\npayload={}\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"GET\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "StT0RbVXB7kgL6U1njFP7",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/versions?hardware_id=string&product=string&license_key=string&username=string\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "O5TXrDheiYbVU5SAC4R6e"
  },
  "description": "Returns metadata on all the available versions of a product",
  "currentNewParameter": {
    "label": "Query Parameter",
    "value": "queryParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4versions",
  "legacyHash": "xa6J4lLjJVcbRUA81DGQu"
}
```
:::

:::hint{type="info"}
Product versions are returned up to the existing **maintenance\_period** *or* **validity\_period** on the license. If those fields are not defined on a license, all versions will be returned by default.
:::

## Schema

### Request Query Parameters

:::CodeblockTabs
```typescript
type GetProductVersionsQueryParameters = {
  
  // required parameters:
  product: string,
  hardware_id: string,
  
  // required for key-based products:
  license_key: string
  
  // required for user-based products:
  username: string
  
  // optional parameters:
  license_id?: string | undefined,
  env?: string | undefined,
  channel?: string | undefined,
}
```

JSON Schema

```json
```
:::

### Response Body

:::CodeblockTabs
```typescript
type GetProductVersionsResponseBody = ({
  version: string,
  release_date: string, // Date string in full ISO 8601 format, e.g. "2024-09-27T23:30:48.016Z"
})[];
```

JSON Schema

```json
```
:::

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

- **Key-based product licenses**: client interactions with the license have to be authorized using a `license_key`
- **User-based product licenses**: the license has a corresponding "license user" instead of a license key. Client interactions with the license have to be authorized using a `username`&#x20;

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions


[title] Get Installation File
[path] License API/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/installation_file",
  "name": "/api/v4/installation_file",
  "method": "GET",
  "request": {
    "pathParameters": [],
    "queryParameters": [
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "string",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "name": "license_key",
        "kind": "optional",
        "type": "string",
        "description": "Required if product is key-based (see section below)",
        "children": []
      },
      {
        "name": "username",
        "kind": "optional",
        "type": "string",
        "description": "Required if product is user based (see section below)",
        "children": []
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "string",
        "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "children": []
      },
      {
        "name": "version",
        "kind": "optional",
        "type": "string",
        "description": "Version string, e.g. \"1.0.0\"",
        "children": []
      },
      {
        "name": "env",
        "kind": "optional",
        "type": "string",
        "description": "Environment identifier, e.g. \"win\", \"win32\", \"win64\", \"mac\", \"linux\", \"linux32\", \"linux64\"",
        "children": []
      },
      {
        "name": "channel",
        "kind": "optional",
        "type": "string",
        "description": "Channel identifier, e.g. \"staging\", \"prod\"",
        "children": []
      }
    ],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "QLX3IFr3FPKeqNnhkuAXk",
        "code": "{\n    \"installation_file\": \"https://www.test.io/file/file.bin\",\n    \"version\": \"1.0.2\",\n    \"requires_version\": null,\n    \"hash_md5\": \"\",\n    \"release_date\": \"2021-04-30T00:00:00.000Z\",\n    \"eula_link\": null,\n    \"release_notes_link\": null,\n    \"size\": null,\n    \"channel\": null\n}",
        "language": "200",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "QLX3IFr3FPKeqNnhkuAXk"
  },
  "examples": {
    "languages": [
      {
        "id": "hlSHwsvIZITxrmCH9iOuB",
        "language": "curl",
        "code": "curl --location --request GET '/api/v4/installation_file?product=string&hardware_id=string&license_key=string&username=string' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string'",
        "customLabel": ""
      },
      {
        "id": "gK7ejk5qLGjiCdKJKrRc0",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'GET',\n   'url': '/api/v4/installation_file?product=string&hardware_id=string&license_key=string&username=string',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   }\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "_oZzwjs4GUBmIh1k1gli0",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar requestOptions = {\n   method: 'GET',\n   headers: myHeaders,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/installation_file?product=string&hardware_id=string&license_key=string&username=string\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "uR1XsyjqY_0ti5ms5tmSy",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/installation_file?product=string&hardware_id=string&license_key=string&username=string\"\n\npayload={}\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"GET\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "SQxtc8U4WJgeULTjwyvIp",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/installation_file?product=string&hardware_id=string&license_key=string&username=string\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "uR1XsyjqY_0ti5ms5tmSy"
  },
  "description": "Returns metadata on the installation file for a product",
  "currentNewParameter": {
    "label": "Query Parameter",
    "value": "queryParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "apiv4installationfile",
  "legacyHash": "KXr5LXfjFzXqlrn5BO4P5"
}
```
:::

:::hint{type="info"}
Product versions are returned up to the existing **maintenance\_period** OR **validity\_period** on the license. If those fields are not defined on a license, all versions will be returned by default.
:::

## Schema

### Request Query Parameters

:::CodeblockTabs
```typescript
type InstallationFileRequestParameters = {
  
  // required parameters:
  product: string,
  hardware_id: string,
  
  // required for key-based products:
  license_key: string
  
  // required for user-based products:
  username: string
  
  // optional parameters:
  license_id?: string | undefined,
  version?: string | undefined,
  env?: string | undefined,
  channel?: string | undefined,
}
```

JSON Schema

```json
```
:::

### Response Body

:::CodeblockTabs
```typescript
type InstallationFileResponseBody = {
    version: string | null,
    environment: string,
    hash_md5: string | null,
    eula_link: string | null,
    release_notes_link: string | null,
    size: string | null,
    requires_version: string | null,
    channel: string | null,
    installation_file: string | null,
    release_date: string | null, // Date string in full ISO 8601 format, e.g. "2024-09-27T23:30:48.016Z"
}
```

JSON Schema

```json
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "version": { "type": ["string", "null"] },
    "environment": { "type": "string" },
    "hash_md5": { "type": ["string", "null"] },
    "eula_link": { "type": ["string", "null"] },
    "release_notes_link": { "type": ["string", "null"] },
    "size": { "type": ["string", "null"] },
    "requires_version": { "type": ["string", "null"] },
    "channel": { "type": ["string", "null"] },
    "installation_file": { "type": ["string", "null"] },
    "release_date": { "type": ["string", "null"] }
  }
}

```
:::

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

- **Key-based product licenses**: client interactions with the license have to be authorized using a `license_key`
- **User-based product licenses**: the license has a corresponding "license user" instead of a license key. Client interactions with the license have to be authorized using a `username`&#x20;

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**license\_key\_or\_license\_user\_required** (400): The license\_key or license user is missing
:::

:::BlockQuote
**active\_license\_required&#x20;**(400): An active license is required
:::

:::BlockQuote
**missing\_headers** (400): Some headers are missing
:::

:::BlockQuote
**missing\_parameters&#x20;**(400): Some parameters are missing in the request: \{ params }
:::

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**license\_not\_found** (400): License with the provided license user not found
:::

:::BlockQuote
**device\_not\_found** (400): An active device matching the hardware\_id not found
:::


[title] Add Consumption
[path] License API/Consumption/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/add_consumption",
  "name": "/api/v4/add_consumption",
  "method": "POST",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "String",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "kind": "optional",
        "name": "license_key",
        "type": "string",
        "children": [],
        "description": "Required if product is key-based (see section below)"
      },
      {
        "kind": "optional",
        "name": "username",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "Number",
        "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "children": []
      },
      {
        "name": "consumptions",
        "kind": "optional",
        "type": "Number",
        "description": "Number of consumptions to add, defaults to 1. May be negative, unless `allow_negative_consumptions` is set to false",
        "children": []
      },
      {
        "name": "max_overages",
        "kind": "optional",
        "type": "string",
        "description": "Maximum number of overages",
        "children": []
      },
      {
        "name": "allow_overages",
        "kind": "optional",
        "type": "string",
        "description": "Allow or disallow overages",
        "children": []
      },
      {
        "name": "event",
        "kind": "optional",
        "type": "Array",
        "description": "An optional array of strings specifying which events will be recorded in the activity log for this request. Currently can be either `consumption_add` (default) or `offline_floating_consumptions_sync` (these 2 events are mutually exclusive)",
        "children": []
      }
    ],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "es8g1cuKJMbNPiIVt9VoF",
        "code": "{\n    \"id\": 12345,\n    \"max_consumptions\": 4,\n    \"total_consumptions\": 9,\n    \"allow_overages\": true,\n    \"max_overages\": 5,\n    \"allow_negative_consumptions\": true,\n    \"allow_unlimited_consumptions\": false,\n    \"reset_consumption\": false,\n    \"consumpton_period\": \"monthly\"\n}",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "7eyIlKSv2QgJcowEsDZ-2",
        "code": "{\n    \"unknown_product\": \"Provided product was not found\",\n    \"license_not_found\": \"License with the provided license user not found\",\n    \"license_not_enabled\": \"The license is not enabled\",\n    \"device_not_found\": \"An active device matching the hardware_id not found.\",\n    \"blacklisted\": \"This device is blacklisted\",\n    \"license_not_active\": \"This license is not activated\",\n    \"unsupported_product_feature\": \"One or more of requested product features     do not exists or they are not enabled on the product.\",\n    \"Feature_not_enough_consumptions\": \"Not enough consumptions left.\"",
        "language": "400",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "es8g1cuKJMbNPiIVt9VoF"
  },
  "examples": {
    "languages": [
      {
        "id": "wgu1oEAMoXM6UPdIpP9rp",
        "language": "curl",
        "code": "curl --location --request POST '/api/v4/add_consumption' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string' \\\n--data-raw '{\"hardware_id\":\"String\",\"product\":\"string\",\"license_key\":\"string\",\"username\":\"string\",\"consumptions\":\"Number\",\"max_overages\":\"string\",\"allow_overages\":\"string\"}'",
        "customLabel": ""
      },
      {
        "id": "6JDkeVkhOJ8QsOpTs-wxs",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'POST',\n   'url': '/api/v4/add_consumption',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   },\n   body: '{\"hardware_id\":\"String\",\"product\":\"string\",\"license_key\":\"string\",\"username\":\"string\",\"consumptions\":\"Number\",\"max_overages\":\"string\",\"allow_overages\":\"string\"}'\n\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "upcYWe4wofrLDc4o8p3O4",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar raw = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"consumptions\\\":\\\"Number\\\",\\\"max_overages\\\":\\\"string\\\",\\\"allow_overages\\\":\\\"string\\\"}\";\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/add_consumption\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "5HMrN8q1YgMPoJbyvSgcy",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/add_consumption\"\n\npayload = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"consumptions\\\":\\\"Number\\\",\\\"max_overages\\\":\\\"string\\\",\\\"allow_overages\\\":\\\"string\\\"}\"\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "UYShjXCMbSacZO6LiPQbJ",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/add_consumption\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\nrequest.body = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\",\\\"consumptions\\\":\\\"Number\\\",\\\"max_overages\\\":\\\"string\\\",\\\"allow_overages\\\":\\\"string\\\"}\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "5HMrN8q1YgMPoJbyvSgcy"
  },
  "description": "Adds 1 or more consumptions to a license (only for consumption-type licenses)\n",
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4addconsumption",
  "legacyHash": "1sF5hKcO06EoFz7X5H7Uq"
}
```
:::

## Schema

### Request Body

:::CodeblockTabs
```typescript
type AddConsumptionRequestBody = ({
  
  // required for key-based products:
  license_key: string,
 
} | { 
  // required for user-based products:
  username: string,

}) & {
  // required parameters:
  product: string,
  hardware_id: string,
  
  // optional parameters:
  license_id?: string | undefined,
  consumptions?: number | undefined,
  max_overages?: number | undefined,
  allow_overages?: boolean | undefined,
  event?: ('consumption_add' | 'offline_floating_consumptions_sync')[] | undefined,
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "allOf": [
    {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "license_key": { "type": "string" }
          },
          "required": ["license_key"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "username": { "type": "string" }
          },
          "required": ["username"],
          "additionalProperties": false
        }
      ]
    },
    {
      "type": "object",
      "properties": {
        "hardware_id": { "type": "string" },
        "product": { "type": "string" },
        "license_id": { "type": "number" },
        "consumptions": { "type": "number" },
        "max_overages": { "type": "number" },
        "allow_overages": { "type": "number" },
        "event": {
          "type": "array",
          "items": { "type": "string", "enum": ["consumption_add", "offline_floating_consumptions_sync"] },
          "minItems": 1,
          "not": {
            "allOf": [
              { "contains": { "const": "consumption_add" } },
              { "contains": { "const": "offline_floating_consumptions_sync" } }
            ]
          }
        }
      },
      "required": ["hardware_id", "product"],
      "additionalProperties": false
    }
  ]
}
```
:::

### Response Body

:::CodeblockTabs
```typescript
type AddConsumptionResponseBody = {
  id: number,
  max_consumptions: number,
  total_consumptions: number,
  allow_unlimited_consumptions: boolean,
  allow_negative_consumptions: boolean,
  allow_overages: boolean,
  max_overages: number,
  reset_consumption: boolean,
  consumption_period: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": { "type": "number" },
    "max_consumptions": { "type": "number" },
    "total_consumptions": { "type": "number" },
    "allow_unlimited_consumptions": { "type": "boolean" },
    "allow_negative_consumptions": { "type": "boolean" },
    "allow_overages": { "type": "boolean" },
    "max_overages": { "type": "number" },
    "reset_consumption": { "type": "boolean" },
    "consumption_period": { "type": [ "string", "null" ], "enum": [ "daily", "weekly", "monthly", "annually", null ] },
  },
  "required": [
    "id",
    "max_consumptions",
    "total_consumptions",
    "allow_unlimited_consumptions",
    "allow_negative_consumptions",
    "allow_overages",
    "max_overages",
    "reset_consumption",
    "consumption_period"
  ],
  "additionalProperties": false
}

```
:::

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

- **Key-based product licenses**: client interactions with the license have to be authorized using a `license_key`
- **User-based product licenses**: the license has a corresponding "license user" instead of a license key. Client interactions with the license have to be authorized using a `username`&#x20;

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**license\_not\_found** (400): License with the provided license user not found
:::

:::BlockQuote
**license\_not\_active** (400): The license is not active
:::

:::BlockQuote
**license\_not\_enabled** (400): The license is not enabled
:::

:::BlockQuote
**license\_not\_consumption&#x20;**(400): The license needs to be of consumption type
:::

:::BlockQuote
**license\_not\_enough\_consumptions** (400): Not enough consumptions left
:::

:::BlockQuote
**negative\_consumptions\_not\_allowed** (400): Negative consumptions not allowed
:::

:::BlockQuote
**device\_not\_found&#x20;**(400): An active device matching the hardware\_id not found
:::

:::BlockQuote
**blacklisted** (400): This device is blacklisted
:::


[title] Single Sign-On URL
[path] License API/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/sso_url",
  "name": "/api/v4/sso_url",
  "method": "GET",
  "request": {
    "pathParameters": [],
    "queryParameters": [
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "kind": "required",
        "name": "customer_account_code",
        "type": "string",
        "children": [],
        "description": "The customer account code to which SSO provider is configured "
      },
      {
        "name": "response_type",
        "kind": "optional",
        "type": "string",
        "description": "Determines the type of OAuth grant - Code Grant or Implicit. If specified, must be either \"code\" or \"token\". Defaults to \"code\"",
        "": "Determines the type of OAuth grant - Code Grant or Implicit. If specified, must be either \"code\" or \"token\". Defaults to \"code\""
      },
      {
        "name": "redirect_uri",
        "kind": "optional",
        "type": "string",
        "description": "This parameter is used if you have multiple SSO redirect URIs enabled (as opposed to a single URI, which is the default). If this is the case, you will need to provide the redirect_uri both in this request, and when using the SSO token/code during authorization on endpoints supporting SSO ",
        "": "This parameter is used if you have multiple SSO redirect URIs enabled (as opposed to a single URI, which is the default). If this is the case, you will need to provide the redirect_uri both in this request, and when using the SSO token/code during authorization on endpoints supporting SSO "
      }
    ],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "QLX3IFr3FPKeqNnhkuAXk",
        "code": "{\n  \"url\": \"https://auth.licensespring.com/realms/user-portal/protocol/openid-connect/auth?scope=openid&response_type=code&client_id=license-users&redirect_uri=http://localhost&kc_idp_hint=foo-bar\",\n  \"openid_configuration\": {\n    \"issuer\": \"https://auth.licensespring.com/realms/user-portal\",\n    \"end_session_endpoint\": \"https://auth.licensespring.com/realms/user-portal/protocol/openid-connect/logout\",\n    \"token_endpoint\": \"https://auth.licensespring.com/realms/user-portal/protocol/openid-connect/token\",\n    \"introspection_endpoint\": \"https://auth.licensespring.com/realms/user-portal/protocol/openid-connect/token/introspect\"\n  }\n}",
        "language": "200",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "QLX3IFr3FPKeqNnhkuAXk"
  },
  "examples": {
    "languages": [
      {
        "id": "fWq6rETGNTdjvOy3Yy9xR",
        "language": "curl",
        "code": "curl --location --request GET '/api/v4/sso_url?product=string&customer_account_code=string' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string'",
        "customLabel": ""
      },
      {
        "id": "H5Pys_rDZ7Mo7mm8WtVId",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'GET',\n   'url': '/api/v4/sso_url?product=string&customer_account_code=string',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   }\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "n_MHXjHJe2mzM1k6yD8uc",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar requestOptions = {\n   method: 'GET',\n   headers: myHeaders,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/sso_url?product=string&customer_account_code=string\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "bAtVMJtyGbLMIFgZ7Tksg",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/sso_url?product=string&customer_account_code=string\"\n\npayload={}\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"GET\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "2zGvSjg8WuB-f1UQYOv5Y",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/sso_url?product=string&customer_account_code=string\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "fWq6rETGNTdjvOy3Yy9xR"
  },
  "description": "Returns the Single Sign-On Url for license user authorization",
  "currentNewParameter": {
    "label": "Query Parameter",
    "value": "queryParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "apiv4ssourl",
  "legacyHash": "3QyxStddM6VomxdFFOZw6"
}
```
:::

## Authorization method

By default, the authorization method used for SSO is **Authorization code grant**. After calling the SSO url, the returned url's query parameter `code` is the value used for SSO-authenticating requests to the API.

Alternatively you may also use the **Implicit grant&#x20;**&#x6D;ethod (by specifying `response_type=token`), which attaches user pool tokens (id\_token, access\_token, expires\_in and token\_type) to the redirect\_uri once the user is verified. The **id\_token** then can be used when Single Sign On server as authentification for license user in [**Activate License (Online Method)**](docId\:Mt2yGm6CJzh2bumU-Gfww)****

## Schema

### Request Query Parameters

:::CodeblockTabs
```typescript
type SSOURLRequestParams = {
  product: string,
  customer_account_code: string,
  response_type?: 'code' | 'token' | undefined
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "product": { "type": "string" },
    "customer_account_code": { "type": "string" },
    "response_type": { "type": "string", "enum": ["code", "token"] }
  },
  "required": ["product", "customer_account_code"],
  "additionalProperties": false
}
```
:::

### Response Body

:::CodeblockTabs
```typescript
type SSOURLResponseBody = {
  url: string,
  openid_configuration: {
    issuer: string,
    end_session_endpoint: string,
    token_endpoint: string,
    introspection_endpoint: string,
  }
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "url": { "type": "string" },
    "openid_configuration": {
      "type": "object",
      "properties": {
        "issuer": { "type": "string" },
        "end_session_endpoint": { "type": "string" },
        "token_endpoint": { "type": "string" },
        "introspection_endpoint": { "type": "string" }
      }
    }
  },
  "required": ["url"],
  "additionalProperties": false
}
```
:::

The response object contains the SSO URL and an `openid_configuration` object specifying the URLs used by the OpenID-compatible authentication service.

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**missing\_headers** (400): Some headers are missing
:::

:::BlockQuote
**authorization\_missing\_params** (400): Some parameters are missing in the authorization: \{ params }
:::


[title] Borrow Floating License
[path] License API/Floating/License/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/floating/borrow",
  "name": "/api/v4/floating/borrow",
  "method": "POST",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "String",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "String",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "name": "borrowed_until",
        "kind": "required",
        "type": "string",
        "description": "Timestamp until license is borrowed. ISO 8601 format (always in UTC timezone)",
        "children": []
      },
      {
        "kind": "optional",
        "name": "license_key",
        "type": "string",
        "children": [],
        "description": "Required if product is key-based (see section below)"
      },
      {
        "kind": "optional",
        "name": "username",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "name": "password",
        "kind": "optional",
        "type": "string",
        "description": "Required if product is user based (see section below)",
        "children": []
      },
      {
        "name": "id_token",
        "kind": "optional",
        "type": "string",
        "description": "Required if using SSO with Implicit grant authorization. This is the id_token received from the SSO.",
        "": "Required if using SSO with Implicit grant authorization. This is the id_token received from the SSO."
      },
      {
        "name": "code",
        "kind": "optional",
        "type": "string",
        "description": "Required if using SSO with Authorization code grant. This is the code received from the SSO.",
        "": "Required if using SSO with Authorization code grant. This is the code received from the SSO."
      },
      {
        "name": "customer_account_code",
        "kind": "optional",
        "type": "string",
        "description": "Required if using SSO. This is the customer_account_code to which SSO provider is configured.",
        "": "Required if using SSO. This is the customer_account_code to which SSO provider is configured."
      },
      {
        "name": "redirect_uri",
        "kind": "optional",
        "type": "string",
        "description": "Required if using SSO with multiple redirect URIs enabled. This value is the redirect URI you used to obtain the SSO token or code",
        "": "Required if using SSO with multiple redirect URIs enabled. This value is the redirect URI you used to obtain the SSO token or code"
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "Number",
        "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "children": []
      }
    ],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "es8g1cuKJMbNPiIVt9VoF",
        "language": "200",
        "code": "{\n    \"borrowed_until\": \"2022-05-06T00:00:00Z\",\n    \"max_borrow_time\": 48,\n    \"device_id\": 1648212707135009,\n    \"license_id\": 1622536481402629,\n    \"floating_in_use_devices\": 0,\n}",
        "customLabel": ""
      },
      {
        "id": "7eyIlKSv2QgJcowEsDZ-2",
        "language": "400",
        "code": "{\n    \"unknown_product\": \"Provided product was not found\",\n    \"license_not_found\": \"License with the provided license user not found\",\n    \"license_not_enabled\": \"The license is not enabled\",\n    \"blacklisted\": \"This device is blacklisted\",\n    \"device_not_found\": \"An active device matching the hardware_id not found.\",\n\n    \ndodaj jos",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "es8g1cuKJMbNPiIVt9VoF"
  },
  "examples": {
    "languages": [
      {
        "id": "V0XPpDWJ6Z-prQFzb1iCk",
        "language": "curl",
        "code": "curl --location --request POST '/api/v4/floating/borrow' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string' \\\n--data-raw '{\"hardware_id\":\"String\",\"product\":\"string\",\"license_key\":\"string\",\"username\":\"string\"}'",
        "customLabel": ""
      },
      {
        "id": "QSGFqLS9Yj7eeCnvEaKJe",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'POST',\n   'url': '/api/v4/floating/borrow',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   },\n   body: '{\"hardware_id\":\"String\",\"product\":\"string\",\"license_key\":\"string\",\"username\":\"string\"}'\n\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "HL5nweu5_Mt8Sh2FqtX-2",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar raw = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\"}\";\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/floating/borrow\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "0QrYgeoue7U2OB9d3-uhC",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/floating/borrow\"\n\npayload = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\"}\"\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "A7K8gbzDnazn4Oq1-rZrI",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/floating/borrow\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\nrequest.body = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\"}\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "V0XPpDWJ6Z-prQFzb1iCk"
  },
  "description": "Borrows a floating cloud license\n",
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4floatingborrow",
  "legacyHash": "bf3LMlNO9PSQ6WjdwzSpZ"
}
```
:::

:::hint{type="info"}
Send null as a value for borrowed\_until if you wan't to set borrowed\_until to max\_borrow\_time from now + max\_borrow\_time value defined on a license.
:::

## Schema

### Request Body

:::CodeblockTabs
```typescript
type BorrowFloatingLicenseRequestBody = {
  
  // required parameters:
  product: string,
  hardware_id: string,
  
  /**
   * `borrowed_until` is a string in ISO 8601 format (always in UTC timezone).
   * It contains a date component and optional time component, e.g.:
   * "2024-09-27T23:30:48.016Z"
   * "2024-09-27 23:30:48.016"
   * "2024-09-27 23:30:48"
   * "2024-09-27 23:30"
   * "2024-09-27"
   */
  borrowed_until: string,
  
  // required for key-based products:
  license_key?: string,
  
  // required for user-based products:
  username?: string,
  password?: string,
  
  // required for SSO with Implicit grant authorization:
  id_token?: string,
  
  // required for SSO with Authorization code grant:
  code?: string,
  
  // required for SSO with either authorization method:
  customer_acount_id?: string,
  
  // optional parameters:
  license_id?: string | undefined,
}
```

JSON Schema

```json
```
:::

### Response Body

:::CodeblockTabs
```typescript
type BorrowFloatingLicenseResponseBody = {
    borrowed_until: string, // date in ISO8061 format
    max_borrow_time: number, // hours
    device_id: number,
    license_id: number,
    floating_in_use_devices: number,
}
```

JSON Schema

```json
```
:::

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

- **Key-based product licenses**: client interactions with the license have to be authorized using a `license_key`
- **User-based product licenses**: the license has a corresponding "license user" instead of a license key. Client interactions with the license have to be authorized using a `username` and `password`

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**missing\_headers** (400): Some headers are missing
:::

:::BlockQuote
**missing\_parameters&#x20;**(400): Some parameters are missing in the request: \{ params }.
:::

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**license\_not\_found&#x20;**(400): License with the provided license user not found
:::

:::BlockQuote
**license\_not\_active** (400): The license is not active
:::

:::BlockQuote
**license\_not\_enabled** (400): The license is not enabled
:::

:::BlockQuote
**license\_borrow\_not\_allowed** (400): License does not allow borrowing
:::

:::BlockQuote
**borrow\_until\_not\_valid** (400): Borrow until field is not valid
:::

:::BlockQuote
**device\_not\_found** (400): An active device matching the hardware\_id not found
:::

:::BlockQuote
**blacklisted** (400): This device is blacklisted
:::

:::BlockQuote
**floating\_not\_available** (400): No available slots for floating license
:::


[title] Get Device Variables
[path] License API/Device Variables/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/get_device_variables",
  "name": "/api/v4/get_device_variables",
  "method": "GET",
  "request": {
    "pathParameters": [],
    "queryParameters": [
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "string",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "name": "license_key",
        "kind": "optional",
        "type": "string",
        "description": "Required if product is key-based (see section below)",
        "children": []
      },
      {
        "name": "username",
        "kind": "optional",
        "type": "string",
        "description": "Required if product is user based (see section below)",
        "children": []
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "Number",
        "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "children": []
      }
    ],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "QLX3IFr3FPKeqNnhkuAXk",
        "code": "[\n    {\n        \"id\": 2155,\n        \"value\": \"t\",\n        \"variable\": \"0\",\n        \"created_at\": \"2021-10-13T10:57:25.000Z\",\n        \"device_id\": 1630390110774029\n    },\n    {\n        \"id\": 2156,\n        \"value\": \"e\",\n        \"variable\": \"1\",\n        \"created_at\": \"2021-10-13T10:57:25.000Z\",\n        \"device_id\": 1630390110774029\n    }\n]",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "r7pnaNGfLVC8RZ1IcgRV8",
        "code": "",
        "language": "404",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "QLX3IFr3FPKeqNnhkuAXk"
  },
  "examples": {
    "languages": [
      {
        "id": "323H9fsg3s2WTlqpUFwcw",
        "language": "curl",
        "code": "curl --location --request GET '/api/v4/get_device_variables?product=string&hardware_id=string&license_key=string&username=string' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string'",
        "customLabel": ""
      },
      {
        "id": "gFsMroK81X7QJhcCI7N5-",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'GET',\n   'url': '/api/v4/get_device_variables?product=string&hardware_id=string&license_key=string&username=string',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   }\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "fPUFj2_AjMISJNlSKZQ0M",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar requestOptions = {\n   method: 'GET',\n   headers: myHeaders,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/get_device_variables?product=string&hardware_id=string&license_key=string&username=string\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "watpnUYZW3a2Uiwd7w88A",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/get_device_variables?product=string&hardware_id=string&license_key=string&username=string\"\n\npayload={}\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"GET\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "vtUz001VgHw8WMmiI58Lo",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/get_device_variables?product=string&hardware_id=string&license_key=string&username=string\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "watpnUYZW3a2Uiwd7w88A"
  },
  "description": "Returns metadata variables assigned to a device",
  "currentNewParameter": {
    "label": "Query Parameter",
    "value": "queryParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4getdevicevariables",
  "legacyHash": "J9eFytSP-LT_ZxPugZjjU"
}
```
:::

## Schema

### Request Query Parameters

:::CodeblockTabs
```typescript
type GetDeviceVariablesRequestParameters = {
  
  // required parameters:
  product: string,
  hardware_id: string,
  
  // required for key-based products:
  license_key: string,
  
  // required for user-based products:
  username: string,
  
  // optional parameters:
  license_id?: string | undefined,
}
```

JSON Schema

```json
```
:::

### Response Body

:::CodeblockTabs
```typescript
type GetDeviceVariablesResponseBody = ({
    variable: string,
    value: string | number | boolean,
    device_id: number,
    created_at: number, // UNIX Timestamp in milliseconds, e.g. 1737128752745
})[];
```

JSON Schema

```json
```
:::

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

- **Key-based product licenses**: client interactions with the license have to be authorized using a `license_key`
- **User-based product licenses**: the license has a corresponding "license user" instead of a license key. Client interactions with the license have to be authorized using a `username`&#x20;

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**license\_not\_found** (400): License with the provided license user not found
:::

:::BlockQuote
**license\_not\_active&#x20;**(400): The license is not active
:::

:::BlockQuote
**license\_not\_enabled** (400): The license is not enabled
:::

:::BlockQuote
**device\_not\_found** (400): An active device matching the hardware\_id not found
:::

:::BlockQuote
**blacklisted** (400): This device is blacklisted
:::


[title] List License Users for Customer
[path] License API/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/customer_license_users",
  "name": "/api/v4/customer_license_users",
  "method": "GET",
  "request": {
    "pathParameters": [],
    "queryParameters": [
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "kind": "required",
        "name": "customer",
        "type": "string",
        "children": [],
        "description": " Attach the assigned license user email (eq. user@example.com)"
      }
    ],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "QLX3IFr3FPKeqNnhkuAXk",
        "code": "{\n    \"customer\": {\n        \"email\": \"test@example.com\",\n        \"first_name\": \"\",\n        \"last_name\": \"\",\n        \"company_name\": \"\",\n        \"phone\": \"\",\n        \"reference\": \"\",\n        \"address\": \"\",\n        \"postcode\": \"\",\n        \"city\": \"\",\n        \"country\": \"\",\n        \"state\": \"\"\n    },\n    \"users\": [\n        {\n            \"email\": \"test1@example.com\",\n            \"is_active\": true,\n            \"first_name\": \"\",\n            \"last_name\": \"\",\n            \"phone_number\": \"\",\n            \"is_initial_password\": true,\n            \"initial_password\": \"t218_uv@\",\n            \"license_id\": 34524352345,\n            \"order_store_id\": \"67e58562adfsfsdf1aff4b1f551d30326\",\n            \"order_id\": 45367563535423\n        },\n        {\n            \"email\": \"test2@example.com\",\n            \"is_active\": true,\n            \"first_name\": \"0\",\n            \"last_name\": \"0\",\n            \"phone_number\": \"0\",\n            \"is_initial_password\": false,\n            \"initial_password\": \"\",\n            \"license_id\": 786856745645,\n            \"order_store_id\": \"gdfge34r4fqf44qqrf43f\",\n            \"order_id\": 653456345635\n        }\n    ]\n}",
        "language": "200",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "QLX3IFr3FPKeqNnhkuAXk"
  },
  "examples": {
    "languages": [
      {
        "id": "rKTBUaDyllWFz1VU8Nl5P",
        "language": "curl",
        "code": "curl --location --request GET '/api/v4/customer_license_users?product=string&customer=string' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string'",
        "customLabel": ""
      },
      {
        "id": "IvWgKp-7mCj4IukJVNqug",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'GET',\n   'url': '/api/v4/customer_license_users?product=string&customer=string',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   }\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "72eeqkOXHAUg8CdcCOmYt",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar requestOptions = {\n   method: 'GET',\n   headers: myHeaders,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/customer_license_users?product=string&customer=string\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "q4I-eqUjgSBRZ5cUExAgW",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/customer_license_users?product=string&customer=string\"\n\npayload={}\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"GET\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "cNfu8WgDfp_v9yJ3B-7t0",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/customer_license_users?product=string&customer=string\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "q4I-eqUjgSBRZ5cUExAgW"
  },
  "description": "Returns a list of all license users assigned to licenses belonging to the requested customer (only for user-based products)",
  "currentNewParameter": {
    "label": "Query Parameter",
    "value": "queryParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4customerlicenseusers",
  "legacyHash": "CmWOBVDKJk6PiXyQgU2lX"
}
```
:::

## Schema

### Request Query Parameters

:::CodeblockTabs
```typescript
type LicenseUsersForCustomerRequestParams = {
  product: string,
  customer: string,
}
```

JSON Schema

```json
```
:::

### Response Body

:::CodeblockTabs
```typescript
type LicenseUsersForCustomerResponseBody = {
  customer: {
    address: string,
    city: string,
    company_name: string,
    country: string,
    customer_account: string | null,
    email: string,
    first_name: string,
    last_name: string,
    phone: string,
    postcode: string,
    reference: string,
    state: string,
    metadata: JSON,
  },
  users: ({
    email: string,
    first_name: string,
    initial_password: string,
    is_active: boolean,
    is_initial_password: boolean,
    last_name: string,
    license_id: number,
    max_activations: number,
    order_id: number,
    order_store_id: string,
    phone_number: string,
    total_activations: number,
  })[]
}
```

JSON Schema

```json
```
:::

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**missing\_headers** (400): Some headers are missing
:::

:::BlockQuote
**invalid\_product\_auth\_method** (400): Product authorization method is invalid: \{ params }.
:::


[title] Consumption
[path] License API/

A consumption is a type of agreement that governs the use of a product or service. There are two main types of consumption licenses: those that include consumptions on the **license** and those that cover the consumption of **features**.

:::hint{type="info"}
`allow_unlimited_consumption` always has priority over `max_overages`, i.e. if `allow_unlimited_consumption` is set to **true** then `max_overages` doesn't have any effect.
:::


[title] License
[path] License API/Floating/

## Floating Licenses

A floating license, also known as a concurrent license, is a popular form of software management license that allows multiple users to utilize a program or service at the same time, but only up to a predetermined **maximum number** of simultaneous users. One notable feature of a floating license is its "**borrow**" and "**release**" capability.

Here you can find more details about [**Floating Licenses**](docId:4aUNyPIaL8I2te4NypPx7)


[title] Device Variables
[path] License API/

Device variables play a crucial role in data exchange by enabling the transfer of information from the device level back into the platform, facilitating a two-way communication channel that empowers real-time monitoring, control, and analysis.

For more information, see our [**Device Variables Usage**](docId\:lXluz2SxZff0VhPKXCI5w).

[title] Trial Key
[path] License API/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/trial_key",
  "name": "/api/v4/trial_key ",
  "method": "GET",
  "request": {
    "pathParameters": [],
    "queryParameters": [
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "kind": "optional",
        "name": "email",
        "type": "string",
        "children": [],
        "description": "Required if product is user based. Attach the assigned license user email (eq. user@example.com)"
      },
      {
        "name": "license_policy",
        "kind": "optional",
        "type": "string",
        "description": "Sets license policy (license policy code), if omited the default license policy for the product will be used",
        "children": []
      },
      {
        "name": "first_name",
        "kind": "optional",
        "type": "string",
        "description": "Optional. For user-based product licenses only",
        "children": []
      },
      {
        "name": "last_name",
        "kind": "optional",
        "type": "string",
        "description": "Optional. For user-based product licenses only",
        "children": []
      },
      {
        "name": "phone",
        "kind": "optional",
        "type": "string",
        "description": "Optional. For user-based product licenses only",
        "children": []
      },
      {
        "name": "password",
        "kind": "optional",
        "type": "string",
        "description": "Only for user-based licenses: Sets the license user's password. If not provided, a random password will be generated and returned in the response",
        "children": []
      }
    ],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "QLX3IFr3FPKeqNnhkuAXk",
        "code": "{\n    \"license_key\": \"T7GB-C4JX-4Y8R-1234\",\n    \"id\": 1737130277841509,\n    \"order_id\": 1737130277837489,\n    \"product_id\": 1,\n    \"created_at\": 1737130277925,\n    \"updated_at\": 1737130277925,\n    \"max_activations\": 1,\n    \"times_activated\": 0,\n    \"is_trial\": true,\n    \"active\": false,\n    \"enabled\": true,\n    \"trial_days\": 15,\n    \"license_type\": \"time-limited\",\n    \"max_transfers\": 0,\n    \"prevent_vm\": false,\n    \"enable_maintenance_period\": false,\n    \"maintenance_duration\": null,\n    \"metadata\": {},\n    \"is_hardware_key_auth\": false,\n    \"validity_period\": null,\n    \"LicenseProductFeatures\": [\n        {\n            \"id\": \"1737130277926519\",\n            \"product_feature_id\": 5,\n            \"max_consumption\": 10,\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"reset_consumption\": false,\n            \"consumption_period\": null,\n            \"expiry_date\": null,\n            \"metadata\": {},\n            \"is_floating\": false,\n            \"is_floating_cloud\": false\n        }\n    ],\n    \"LicenseCustomFields\": [],\n    \"license\": \"T7GB-C4JX-4Y8R-1234\"\n}",
        "language": "200",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "QLX3IFr3FPKeqNnhkuAXk"
  },
  "examples": {
    "languages": [
      {
        "id": "GCdqGE3Uarg-ovc11AFKF",
        "language": "curl",
        "code": "curl --location --request GET '/api/v4/trial_key?hardware_id=string&product=string&license_key=string&username=string' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string'",
        "customLabel": ""
      },
      {
        "id": "kVmRuRWFg1WdVHBr_jJsI",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'GET',\n   'url': '/api/v4/trial_key?hardware_id=string&product=string&license_key=string&username=string',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   }\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "VzSNg-xq9B50TtFX7fGlE",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar requestOptions = {\n   method: 'GET',\n   headers: myHeaders,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/trial_key?hardware_id=string&product=string&license_key=string&username=string\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "FANx6WPBmq3niAudJgpuM",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/trial_key?hardware_id=string&product=string&license_key=string&username=string\"\n\npayload={}\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"GET\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "Z5q0sg9XmQTNVHKXuCjN_",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/trial_key?hardware_id=string&product=string&license_key=string&username=string\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "FANx6WPBmq3niAudJgpuM"
  },
  "description": "Creates and returns a trial license",
  "currentNewParameter": {
    "label": "Query Parameter",
    "value": "queryParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4trialkey",
  "legacyHash": "zrrgN4VcOCK3c5SxI1DGv"
}
```
:::

:::hint{type="danger"}
For a trial license to be created, the product must have trial licenses enabled by setting `allow_trial` to true.

By default, the same combination of hardwareID and product will generate the same trial key. This ensures that users cannot obtain multiple trial keys on the same device.

If you want to permit multiple trial licenses on the same device, you can enable this feature by adjusting the **Allow multiple licenses on trial** setting in the vendor platform under your company account settings.
:::

## Schema

### Request Query Parameters

:::CodeblockTabs
```typescript
type TrialKeyRequestParameters = {
  
  // required parameters:
  product: string,
  hardware_id: string,
  
  // required for key-based products:
  license_key: string,
  
  // required for user-based products:
  email: string,
  
  // optional for user-based products:
  password?: string | undefined,
  
  // optional property:
  license_policy?: string | undefined,
  
  // if any of the following optional properties is set, a Customer is created for (or associated to) this Trial Key request:
  first_name?: string | undefined,
  last_name?: string | undefined,
  phone?: string | undefined,
  phone?: string | undefined,
  address?: string | undefined,
  postcode?: string | undefined,
  state?: string | undefined,
  country?: string | undefined,
  city?: string | undefined,
  reference:?: string | undefined,
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "product": { "type": "string" },
    "hardware_id": { "type": "string" },
    "license_key": { "type": "string" },
    "email": { "type": "string", "format": "email" },
    "password": { "type": ["string"] },
    "license_policy": { "type": ["string"] },
    "first_name": { "type": ["string"] },
    "last_name": { "type": ["string"] },
    "phone": { "type": ["string"] },
    "address": { "type": ["string"] },
    "postcode": { "type": ["string"] },
    "state": { "type": ["string"] },
    "country": { "type": ["string"] },
    "city": { "type": ["string"] },
    "reference": { "type": ["string"] }
  },
  "oneOf": {
    "required": { ["product", "hardware_id", "license_key"] },
    "required": { ["product", "hardware_id", "email"] }
  },
  "additionalProperties": false
}

```
:::

### Response Body

:::hint{type="info"}
The response from this endpoint will differ depending in whether a trial license already exists for the requested product, hardware ID and email\* (\*if using user-based license)
:::

1.**&#x20;If a new trial license is being created**

:::CodeblockTabs
```typescript
type TrialKeyResponseBody = {

  id: number,
  license_type: 'perpetual' | 'time-limited' | 'consumption' | 'subscription',
  order_id: number,
  product_id: number,
  max_activations: number,
  times_activated: number,
  is_trial: true,
  active: boolean,
  enabled: boolean,
  max_transfers: number,
  trial_days: number,
  maintenance_duration: string | null, // Length of time expressed in days, months or years, e.g. 5d, 2m, 3y
  validity_period: string | null, // Date string in full ISO 8601 format, e.g. "2024-09-27T23:30:48.016Z"
  enable_maintenance_period: boolean,
  prevent_vm: boolean,
  is_hardware_key_auth: boolean,
  initial_password: string,
  metadata: JSON,
  created_at: number, // UNIX Timestamp in milliseconds
  updated_at: number, // UNIX Timestamp in milliseconds
  
  LicenseProductFeatures: ({
    id: number,
    product_feature_id: number,
    max_consumption: number,
    allow_overages: boolean,
    max_overages: number,
    reset_consumption: number,
    consumption_period: string | null,
    expiry_date: string | null, // Date string in full ISO 8601 format, e.g. "2024-09-27T23:30:48.016Z"
    is_floating: boolean,
    is_floating_cloud: boolean,
    metadata: JSON,
    
    // the following properties are only present if is_floating=true or is_floating_cloud=true
    floating_timeout: number,
    floating_users: number,
  })[],
  
  LicenseCustomFields: {
    product_custom_field_id: number,
    value: string
  }[],
  
  // the following properties are only present for key-based product licenses
  license: string,
  license_key: string,
  
  // the following properties are only present for user-based product licenses
  license_user: string,
  initial_password: string,
  max_license_users: number,
  license_user_id: number | null,
  
  // the following properties are only present if license_type="subscription"
  grace_period: number,
  allow_grace_period: boolean,
  
  // the following properties are only present if license_type="consumption"
  allow_overages: boolean,
  max_overages: number,
  max_consumptions: number,
  valid_duration: null,
  consumption_period: string | null,
  reset_consumption: boolean,
}
```

JSON Schema

```json
```
:::

2\. **If a trial license already exists**

:::CodeblockTabs
```typescript
{
    license_type: 'perpetual' | 'time-limited' | 'consumption' | 'subscription',
    is_trial: true,
    
    // the following property is only present on key-based product licenses
    license: string,
    
    // the following property is only present on user-based product licenses
    license_user: string,
}
```

JSON Schema

```json
```
:::

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**missing\_parameters** (400): Some parameters are missing in the request: \{ params }
:::

:::BlockQuote
**missing\_hardware\_id&#x20;**(400): The hardware\_id missing in the request
:::

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**trial\_not\_allowed&#x20;**(400)\:Product does not allow trial
:::

:::BlockQuote
**email\_missing** (400): An email is missing for user-based product
:::


[title] List Product Features
[path] Management API/Product/Features/

:::ApiMethodV2
```json
{
  "name": "Show all product features the requesting manager has access permissions to.",
  "method": "GET",
  "url": "/api/v1/product-features/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "VPlad6mtXk_5pakfzGJdC",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "VPlad6mtXk_5pakfzGJdC"
  },
  "results": {
    "languages": [
      {
        "id": "ujhI1Wr7pQPvnzpUb0z5_",
        "language": "200",
        "code": "{\n    \"count\": 5,\n    \"next\": null,\n    \"previous\": null,\n    \"results\": [\n        {\n            \"id\": 561,\n            \"created_at\": \"2023-10-30T11:12:13Z\",\n            \"updated_at\": \"2023-10-30T11:12:13Z\",\n            \"name\": \"f0\",\n            \"code\": \"f0\",\n            \"is_deleted\": false,\n            \"feature_type\": \"activation\",\n            \"max_consumption\": 0,\n            \"allow_unlimited_consumptions\": false,\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"reset_consumption\": false,\n            \"consumption_period\": null,\n            \"is_floating\": false,\n            \"is_floating_cloud\": true,\n            \"floating_users\": 8,\n            \"floating_timeout\": 120,\n            \"metadata\": {},\n            \"product\": 1698659666691556\n        },\n        {\n            \"id\": 560,\n            \"created_at\": \"2023-10-30T10:18:51Z\",\n            \"updated_at\": \"2023-10-30T10:22:09Z\",\n            \"name\": \"f1\",\n            \"code\": \"f1\",\n            \"is_deleted\": false,\n            \"feature_type\": \"consumption\",\n            \"max_consumption\": 7,\n            \"allow_unlimited_consumptions\": false,\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"reset_consumption\": false,\n            \"consumption_period\": null,\n            \"is_floating\": true,\n            \"is_floating_cloud\": false,\n            \"floating_users\": 13,\n            \"floating_timeout\": 113,\n            \"metadata\": {},\n            \"product\": 1698659666691556\n        },\n        {\n            \"id\": 559,\n            \"created_at\": \"2023-10-30T10:13:45Z\",\n            \"updated_at\": \"2023-10-30T10:17:56Z\",\n            \"name\": \"f3\",\n            \"code\": \"f3\",\n            \"is_deleted\": false,\n            \"feature_type\": \"consumption\",\n            \"max_consumption\": 10,\n            \"allow_unlimited_consumptions\": false,\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"reset_consumption\": false,\n            \"consumption_period\": \"daily\",\n            \"is_floating\": false,\n            \"is_floating_cloud\": true,\n            \"floating_users\": 10,\n            \"floating_timeout\": 120,\n            \"metadata\": {},\n            \"product\": 1698659666691556\n        },\n        {\n            \"id\": 558,\n            \"created_at\": \"2023-10-30T10:08:05Z\",\n            \"updated_at\": \"2023-10-30T10:08:05Z\",\n            \"name\": \"f4\",\n            \"code\": \"f4\",\n            \"is_deleted\": false,\n            \"feature_type\": \"consumption\",\n            \"max_consumption\": 10,\n            \"allow_unlimited_consumptions\": false,\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"reset_consumption\": false,\n            \"consumption_period\": null,\n            \"is_floating\": false,\n            \"is_floating_cloud\": false,\n            \"floating_users\": 1,\n            \"floating_timeout\": null,\n            \"metadata\": {},\n            \"product\": 1698659666691556\n        },\n        {\n            \"id\": 557,\n            \"created_at\": \"2023-10-30T09:54:47Z\",\n            \"updated_at\": \"2023-10-30T09:54:47Z\",\n            \"name\": \"p\",\n            \"code\": \"p\",\n            \"is_deleted\": false,\n            \"feature_type\": \"activation\",\n            \"max_consumption\": 0,\n            \"allow_unlimited_consumptions\": false,\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"reset_consumption\": false,\n            \"consumption_period\": null,\n            \"is_floating\": false,\n            \"is_floating_cloud\": true,\n            \"floating_users\": 7,\n            \"floating_timeout\": 120,\n            \"metadata\": {},\n            \"product\": 1698659666691556\n        }\n    ]\n}",
        "customLabel": ""
      },
      {
        "id": "M3pDz1JuYnoPO8fWSprfn",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "ujhI1Wr7pQPvnzpUb0z5_"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "show-all-product-features-the-requesting-manager-h",
  "legacyHash": "kdBWIuidpT966crwedAI0"
}
```
:::

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on product custom field or related to the product custom field.

Possible filters:

- `product`
- `metadata`


[title] Add Label to Customer
[path] Management API/Customer/Labels/

:::ApiMethodV2
```json
{
  "name": "Adds a label to customer, if requesting manager has access permissions to it.",
  "method": "POST",
  "url": "/api/v1/customerclabels/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "c9G0lqp1crAgHrBEBju1I",
        "language": "json",
        "code": "{\n    \"customer\": 101,\n    \"customer_label\": 53\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "c9G0lqp1crAgHrBEBju1I"
  },
  "results": {
    "languages": [
      {
        "id": "4mNqjOpFX5l35BNeOfUtP",
        "language": "200",
        "code": "{\n    \"customer\": 101,\n    \"customer_label\": 53\n}",
        "customLabel": ""
      },
      {
        "id": "qKhyX0-x4YDoGwV_8XYP0",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "4mNqjOpFX5l35BNeOfUtP"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "customer",
        "kind": "required",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "customer_label",
        "kind": "required",
        "type": "integer",
        "description": "",
        "": "integer"
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "adds-a-label-to-customer-if-requesting-manager-has",
  "legacyHash": "VHOv4vyd2rrMu2BkorjAT"
}
```
:::


[title] Product
[path] Management API/


[title] Update Product Feature
[path] Management API/Product/Features/

:::ApiMethodV2
```json
{
  "name": "Updates a product feature, if requesting manager has access permissions to it",
  "method": "PATCH",
  "url": "/api/v1/product-features/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "WZ7qlqEehKU7dRgkESw6Q",
        "language": "json",
        "code": "{\n    \"name\": \"f1\",\n    \"code\": \"f1\",\n    \"feature_type\": \"consumption\",\n    \"max_consumption\": 7,\n    \"allow_overages\": false,\n    \"max_overages\": 0,\n    \"reset_consumption\": false,\n    \"consumption_period\": null,\n    \"metadata\": {},\n    \"product\": 1698659666691556,\n    \"is_floating\": true,\n    \"floating_users\":13,\n    \"floating_timeout\":113\n\n\n} \n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "WZ7qlqEehKU7dRgkESw6Q"
  },
  "results": {
    "languages": [
      {
        "id": "YW2vrhKd1zVp-A8sBuQl9",
        "language": "200",
        "code": "{\n    \"id\": 560,\n    \"created_at\": \"2023-10-30T10:18:51Z\",\n    \"updated_at\": \"2023-10-30T10:22:08.887494Z\",\n    \"name\": \"f1\",\n    \"code\": \"f1\",\n    \"is_deleted\": false,\n    \"feature_type\": \"consumption\",\n    \"max_consumption\": 7,\n    \"allow_unlimited_consumptions\": false,\n    \"allow_overages\": false,\n    \"max_overages\": 0,\n    \"reset_consumption\": false,\n    \"consumption_period\": null,\n    \"is_floating\": true,\n    \"is_floating_cloud\": false,\n    \"floating_users\": 13,\n    \"floating_timeout\": 113,\n    \"metadata\": {},\n    \"product\": 1698659666691556\n}",
        "customLabel": ""
      },
      {
        "id": "nhxOA1XDgWEhjNGWE7gL8",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "YW2vrhKd1zVp-A8sBuQl9"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "name",
        "kind": "required",
        "type": "string",
        "description": "ID of the cake to get",
        "": "name"
      },
      {
        "name": "code",
        "kind": "required",
        "type": "string",
        "description": "",
        "": "required"
      },
      {
        "name": "feature_type",
        "kind": "required",
        "type": "string",
        "description": "Choices: activation, consumption.",
        "": "Choices: activation, consumption."
      },
      {
        "name": "max_consumption",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "Parameter name",
        "kind": "optional",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "allow_overages ",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "max_overages",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "reset_consumption",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "consumption_period",
        "kind": "optional",
        "type": "string",
        "description": "Choices: daily, weekly, monthly, annually.",
        "": "Choices: daily, weekly, monthly, annually."
      },
      {
        "name": "product",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "is_floating",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "floating_users",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "floating_timeout",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "metadata",
        "kind": "optional",
        "type": "object",
        "description": "JSON object",
        "": "object",
        "children": [],
        "schema": []
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "updates-a-product-feature-if-requesting-manager-ha",
  "legacyHash": "mSz8ciQdQscAzC06w7Zs4"
}
```
:::


[title] Create Product Feature
[path] Management API/Product/Features/

:::ApiMethodV2
```json
{
  "name": "Creates a product feature, if requesting manager has access permissions to it.",
  "method": "POST",
  "url": "/api/v1/product-features/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "WZ7qlqEehKU7dRgkESw6Q",
        "language": "json",
        "code": "{\n    \"name\": \"f3\",\n    \"code\": \"f3\",\n    \"feature_type\": \"consumption\",\n    \"max_consumption\": 10,\n    \"allow_overages\": false,\n    \"max_overages\": 0,\n    \"reset_consumption\": false,\n    \"consumption_period\": null,\n    \"metadata\": {},\n    \"product\": 1698659666691556,\n    \"is_floating\": true,\n    \"floating_users\":10,\n    \"floating_timeout\":120,\n    \n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "WZ7qlqEehKU7dRgkESw6Q"
  },
  "results": {
    "languages": [
      {
        "id": "YW2vrhKd1zVp-A8sBuQl9",
        "language": "200",
        "code": "{\n    \"id\": 559,\n    \"created_at\": \"2023-10-30T10:13:45.041716Z\",\n    \"updated_at\": \"2023-10-30T10:13:45.041815Z\",\n    \"name\": \"f3\",\n    \"code\": \"f3\",\n    \"is_deleted\": false,\n    \"feature_type\": \"consumption\",\n    \"max_consumption\": 10,\n    \"allow_unlimited_consumptions\": false,\n    \"allow_overages\": false,\n    \"max_overages\": 0,\n    \"reset_consumption\": false,\n    \"consumption_period\": null,\n    \"is_floating\": true,\n    \"is_floating_cloud\": false,\n    \"floating_users\": 10,\n    \"floating_timeout\": 120,\n    \"metadata\": {},\n    \"product\": 1698659666691556\n}",
        "customLabel": ""
      },
      {
        "id": "nhxOA1XDgWEhjNGWE7gL8",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "YW2vrhKd1zVp-A8sBuQl9"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "name",
        "kind": "required",
        "type": "string",
        "description": "",
        "": ""
      },
      {
        "name": "code",
        "kind": "required",
        "type": "string",
        "description": "",
        "": "required"
      },
      {
        "name": "feature_type",
        "kind": "required",
        "type": "string",
        "description": "Choices: activation, consumption.",
        "": "Choices: activation, consumption."
      },
      {
        "name": "max_consumption",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "Parameter name",
        "kind": "optional",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "allow_overages ",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "max_overages",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "reset_consumption",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "consumption_period",
        "kind": "optional",
        "type": "string",
        "description": "Choices: daily, weekly, monthly, annually.",
        "": "Choices: daily, weekly, monthly, annually."
      },
      {
        "name": "product",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "is_floating",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "floating_users",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "floating_timeout",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "metadata",
        "kind": "optional",
        "type": "object",
        "description": "JSON object",
        "": "object",
        "children": [],
        "schema": []
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "creates-a-product-feature-if-requesting-manager-ha",
  "legacyHash": "y-z2EesAGVVGAon101GBE"
}
```
:::


[title] Update Product Custom Field
[path] Management API/Product/Custom Fields/

:::ApiMethodV2
```json
{
  "name": "Updates a product custom field, if requesting manager has access permissions to it.",
  "method": "PATCH",
  "url": "/api/v1/product-custom-fields/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "PnDRMltIkaWDFEOSUSP2P",
        "language": "json",
        "code": "{\n    \"name\": \"cf44\",\n    \"default_value\": \"31232\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "PnDRMltIkaWDFEOSUSP2P"
  },
  "results": {
    "languages": [
      {
        "id": "GEXWewn-PSiVkP5wXbfLn",
        "language": "200",
        "code": "{\n    \"id\": 68,\n    \"name\": \"cf44\",\n    \"data_type\": null,\n    \"default_value\": \"31232\",\n    \"description\": null,\n    \"product\": 1584723961091260\n}",
        "customLabel": ""
      },
      {
        "id": "JcKgYqxSD47e9qq5wMSif",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "GEXWewn-PSiVkP5wXbfLn"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "name",
        "kind": "required",
        "type": "string",
        "description": "ID of the cake to get",
        "": "name"
      },
      {
        "name": "default_value",
        "kind": "required",
        "type": "string",
        "description": "",
        "": "required"
      },
      {
        "name": "product",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "optional"
      },
      {
        "name": "data_type",
        "kind": "optional",
        "type": "string",
        "description": "Choices: number, text, date/time",
        "": "Choices: number, text, date/time"
      },
      {
        "name": "description",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "description"
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "updates-a-product-custom-field-if-requesting-manag",
  "legacyHash": "nraXBpsAhbaDCvTwIyPhI"
}
```
:::


[title] List Customer Labels
[path] Management API/Customer/Labels/

:::ApiMethodV2
```json
{
  "name": "Show all customer labels the requesting manager has access permissions to.",
  "method": "GET",
  "url": "/api/v1/clabels/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "RX3Lr9ppD7Lcvebo85Xdp",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "RX3Lr9ppD7Lcvebo85Xdp"
  },
  "results": {
    "languages": [
      {
        "id": "OVS79XTmtR01Gzj5swra3",
        "language": "200",
        "code": "{\n    \"count\": 5,\n    \"next\": null,\n    \"previous\": null,\n    \"results\": [\n        {\n            \"id\": 52,\n            \"label\": \"Label1\",\n            \"color\": \"#2e86de\",\n            \"company\": 339\n        },\n        ...\n    ]\n}",
        "customLabel": ""
      },
      {
        "id": "4T0ArPIPjGevLl9VJMpVN",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "OVS79XTmtR01Gzj5swra3"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "show-all-customer-labels-the-requesting-manager-ha",
  "legacyHash": "7TMJeSKr3w8oKobf2c5FU"
}
```
:::

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

###


[title] Delete Client
[path] Management API/Untitled/Customer Account/

:::ApiMethodV2
```json
{
  "name": "Delete customer account OAuth client",
  "method": "DELETE",
  "url": "/api/v1/customer-accounts/{id}/client",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "Gr7UObV62paQCjFp1vaE4",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "Gr7UObV62paQCjFp1vaE4"
  },
  "results": {
    "languages": [
      {
        "id": "pml16j1B0GuA6TKOmUrZZ",
        "language": "200",
        "code": "Code: 200 OK",
        "customLabel": ""
      },
      {
        "id": "4Y30G_FFhrOTN4Zz8Z-ho",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "pml16j1B0GuA6TKOmUrZZ"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "delete-customer-account-oauth-client",
  "legacyHash": "htOG9sh011ciYwbYCJueC"
}
```
:::

``

[title] List Products
[path] Management API/Product/

:::ApiMethodV2
```json
{
  "name": "Show all products the requesting manager has access permissions to.",
  "method": "GET",
  "url": "/api/v1/products/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "GsRjw2Q3fZe16a2kq8HgW",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "GsRjw2Q3fZe16a2kq8HgW"
  },
  "results": {
    "languages": [
      {
        "id": "8jueM5JbzF7RkQJL0Fcz3",
        "language": "200",
        "code": "{\n    \"count\": 6,\n    \"next\": null,\n    \"previous\": null,\n    \"results\": [\n        {\n            \"id\": 1584723961091234,\n            \"upgrade_from\": [],\n            \"product_features\": [\n                {\n                    \"id\": 171,\n                    \"created_at\": \"2020-08-26T05:36:46Z\",\n                    \"updated_at\": \"2020-08-26T05:36:46Z\",\n                    \"name\": \"Feature 1\",\n                    \"code\": \"f1\",\n                    \"is_deleted\": false,\n                    \"feature_type\": \"activation\",\n                    \"max_consumption\": 0,\n                    \"allow_overages\": false,\n                    \"max_overages\": 0,\n                    \"reset_consumption\": false,\n                    \"consumption_period\": null\n                },\n                {\n                    \"id\": 172,\n                    \"created_at\": \"2020-08-26T05:37:14Z\",\n                    \"updated_at\": \"2020-08-26T05:37:14Z\",\n                    \"name\": \"Feature 2\",\n                    \"code\": \"f2\",\n                    \"is_deleted\": false,\n                    \"feature_type\": \"consumption\",\n                    \"max_consumption\": 20,\n                    \"allow_overages\": false,\n                    \"max_overages\": 0,\n                    \"reset_consumption\": false,\n                    \"consumption_period\": null,\n                    \"metadata\": {},\n                },\n                {\n                    \"id\": 173,\n                    \"created_at\": \"2020-09-14T11:17:43Z\",\n                    \"updated_at\": \"2020-09-14T11:17:43Z\",\n                    \"name\": \"Feature 3\",\n                    \"code\": \"f3\",\n                    \"is_deleted\": false,\n                    \"feature_type\": \"consumption\",\n                    \"max_consumption\": 2,\n                    \"allow_overages\": false,\n                    \"max_overages\": 0,\n                    \"reset_consumption\": false,\n                    \"consumption_period\": null,\n                    \"metadata\": {},\n                },\n                {\n                    \"id\": 189,\n                    \"created_at\": \"2020-11-13T07:40:53Z\",\n                    \"updated_at\": \"2020-11-13T07:40:53Z\",\n                    \"name\": \"Feature 5\",\n                    \"code\": \"f5\",\n                    \"is_deleted\": false,\n                    \"feature_type\": \"activation\",\n                    \"max_consumption\": 0,\n                    \"allow_overages\": false,\n                    \"max_overages\": 0,\n                    \"reset_consumption\": false,\n                    \"consumption_period\": null,\n                    \"metadata\": {},\n                }\n            ],\n            \"custom_fields\": [\n                {\n                    \"id\": 51,\n                    \"name\": \"Some key\",\n                    \"data_type\": null,\n                    \"default_value\": \"1234\",\n                    \"description\": null\n                },\n                {\n                    \"id\": 60,\n                    \"name\": \"test_name\",\n                    \"data_type\": null,\n                    \"default_value\": \"123\",\n                    \"description\": null\n                },\n                {\n                    \"id\": 61,\n                    \"name\": \"Key with space\",\n                    \"data_type\": null,\n                    \"default_value\": \"123\",\n                    \"description\": null\n                }\n            ],\n            \"installation_files\": [\n                {\n                    \"id\": 733282,\n                    \"created_at\": \"2020-10-13T09:15:22Z\",\n                    \"updated_at\": \"2020-10-13T09:15:22Z\",\n                    \"version\": \"0.1\",\n                    \"full_link\": \"https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf\",\n                    \"filename\": \"dummy.pdf\",\n                    \"release_date\": \"2020-10-09\",\n                    \"enabled\": true,\n                    \"hash_md5\": \"\",\n                    \"environment\": \"linux\"\n                },\n                {\n                    \"id\": 733283,\n                    \"created_at\": \"2020-10-13T09:15:52Z\",\n                    \"updated_at\": \"2020-10-13T09:15:52Z\",\n                    \"version\": \"0.2\",\n                    \"full_link\": \"https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf\",\n                    \"filename\": \"dummy.pdf\",\n                    \"release_date\": \"2020-10-10\",\n                    \"enabled\": true,\n                    \"hash_md5\": \"sonotahash\",\n                    \"environment\": \"linux\"\n                }\n            ],\n            \"created_at\": \"2020-07-03T13:05:25Z\",\n            \"updated_at\": \"2020-07-07T12:35:05Z\",\n            \"product_name\": \"mch\",\n            \"short_code\": \"mch\",\n            \"active\": true,\n            \"valid_duration\": \"\",\n            \"allow_trial\": false,\n            \"trial_days\": 0,\n            \"max_activations\": 1,\n            \"hardware_id_required\": false,\n            \"is_upgrade\": false,\n            \"subscription_duration\": \"\",\n            \"enable_maintenance_period\": false,\n            \"maintenance_duration\": \"\",\n            \"is_floating\": true,\n            \"is_floating_cloud\": false,\n            \"floating_users\": 12,\n            \"floating_timeout\": 120,\n            \"default_license_type\": \"perpetual\",\n            \"is_user_locked\": false,\n            \"is_node_locked\": true,\n            \"max_consumptions\": 1,\n            \"authorization_method\": \"user\",\n            \"prevent_vm\": false,\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"reset_consumption\": false,\n            \"consumption_period\": null,\n            \"is_archived\": false,\n            \"metadata\": {},\n            \"company\": 277\n        },\n        ...\n    ]\n}",
        "customLabel": ""
      },
      {
        "id": "eIK7v4ZemvHLR6Z-pwk8B",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "8jueM5JbzF7RkQJL0Fcz3"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "show-all-products-the-requesting-manager-has-acces",
  "legacyHash": "2SuS6wP3YvwDjmM5xikM8"
}
```
:::

### Query Parameters:

### Ordering:

- `order_by` - Which attribute to order the list by.
  - default ordering is ascending, can be made descending by prefixing the attribute name with `-`
  - Example: `order_by=created_at`
  - Example: `order_by=-created_at`

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Search:

- To search products by name, use the `product_name__icontains`
- To search products by code, use the `short_code__icontains `

### Filtering:

The results can be filtered by various attributes on product or related to the product.

Possible filters:

- `is_archived`
- `short_code`
- `is_bundle`
- `metadata`
- `authorization_method`
- `active`
- `allow_trial`


[title] Delete Product Feature
[path] Management API/Product/Features/

:::ApiMethodV2
```json
{
  "name": "Deletes a single product feature, if requesting manager has access permissions to it.",
  "method": "DELETE",
  "url": "/api/v1/product-features/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "SQdzMwWbZYExllbYG_MXV",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "SQdzMwWbZYExllbYG_MXV"
  },
  "results": {
    "languages": [
      {
        "id": "GfYb0eirX4cFQhqq5RO7P",
        "language": "200",
        "code": "200 OK",
        "customLabel": ""
      },
      {
        "id": "mYAEc1EJH0C25HytV8b-d",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "GfYb0eirX4cFQhqq5RO7P"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "deletes-a-single-product-feature-if-requesting-man",
  "legacyHash": "7xxpxJUEp7mShsSrV-KPH"
}
```
:::

:::hint{type="info"}
This will completely purge the product feature also deleting it from all the licenses. To delete the product feature leaving it intact on licenses just PATCH the is\_deleted field instead.
:::


[title] Retrieve Customer
[path] Management API/Customer/

:::ApiMethodV2
```json
{
  "name": " Retrieves a single customer, if requesting manager has access permissions to it.",
  "method": "GET",
  "url": "/api/v1/customers/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "x1QyMXYHYeNEfHpKTmMfX",
        "language": "json",
        "code": "{\n    \"id\": 620,\n    \"total_orders\": 52,\n    \"total_licenses\": 117,\n    \"labels\": [\n        {\n            \"id\": 3,\n            \"label_id\": 8,\n            \"label\": \"Customer\",\n            \"color\": \"#ff9f43\"\n        },\n        {\n            \"id\": 53,\n            \"label_id\": 34,\n            \"label\": \"Loyal\",\n            \"color\": \"#3a0cd4\"\n        }\n    ],\n    \"customer_account\": null,\n    \"email\": \"tc@tc.com\",\n    \"first_name\": \"Nameo\",\n    \"last_name\": \"\",\n    \"company_name\": \"\",\n    \"phone\": \"\",\n    \"reference\": \"\",\n    \"address\": \"\",\n    \"postcode\": \"\",\n    \"city\": \"\",\n    \"country\": \"\",\n    \"state\": \"\",\n    \"clabels_all\": \"customerloyal\",\n    \"cognito_user_pool_id\": \"\",\n    \"metadata\": {},\n    \"company\": 277,\n    \"license_user\": 1879,\n    \"clabels\": [\n        8,\n        34\n    ]\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "x1QyMXYHYeNEfHpKTmMfX"
  },
  "results": {
    "languages": [
      {
        "id": "PO1PLYwoaOlsVb97xfzFX",
        "language": "200",
        "code": "Code: 200 OK",
        "customLabel": ""
      },
      {
        "id": "EaPZRblYgBX3IttMf8P7g",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "PO1PLYwoaOlsVb97xfzFX"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "retrieves-a-single-customer-if-requesting-manager",
  "legacyHash": "-VzIJUonckfESRG75G9bZ"
}
```
:::

****

[title] Import Customers from CSV
[path] Management API/Customer/

:::hint{type="warning"}
Ensure that all text fields in your CSV use **ASCII characters**. Non-ASCII characters (such as “ä”, “ñ”, or other special symbols) can cause import errors. To avoid issues, remove or replace these characters before uploading your file.
:::

:::ApiMethodV2
```json
{
  "name": "Imports customers from CSV, if requesting manager has access permissions to it.",
  "method": "POST",
  "url": "/api/v1/customers/import_from_csv/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "oRJMf46wjLmAEbSg1BUTU",
        "language": "null",
        "code": "email,first_name,last_name,company_name,phone,reference,address,postcode,state,city,country\nexample1@email.com,Bruce,Willis,ACME Inc.,,ref_user_1,2645 Black Bear Court,70501,Colorado,Lafayette,US\nexample2@email.com,Harry,Potter,Hogwarts,+385913334444,ref_user_1,2110 N. Williamston Rd.,70502,Michigan,Williamston,US",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "oRJMf46wjLmAEbSg1BUTU"
  },
  "results": {
    "languages": [
      {
        "id": "6kfr9iGdee6lUnqa8n8NT",
        "language": "200",
        "code": "{\n    \"job_id\": 10\n}",
        "customLabel": ""
      },
      {
        "id": "IPzkCxvqYNdugOa4GxK2g",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "6kfr9iGdee6lUnqa8n8NT"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "imports-customers-from-csv-if-requesting-manager-h",
  "legacyHash": "freMo4yyVOo-6d0fB6gyc"
}
```
:::

### Content-Type:

Required `Content-Type` is `multipart/form-data` with the following single key-value pair:

- Key: `file`
- Value: `{csv file from which to import}`

### Possible CSV Headers:

- `email`
- `first_name`
- `last_name`
- `company_name`
- `phone`
- `reference`
- `address`
- `postcode`
- `state`
- `city`
- `country`

:::hint{type="info"}
`job_id` from response can be used to query the import result.
:::


[title] Create Customer Label
[path] Management API/Customer/Labels/

:::ApiMethodV2
```json
{
  "name": " Creates a customer label, if requesting manager has access permissions to it.",
  "method": "POST",
  "url": "/api/v1/clabels/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "TmmMznIh3n6-a25Rmnk_3",
        "language": "json",
        "code": "{\n    \"label\": \"Label1\",\n    \"color\": \"#2e86de\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "TmmMznIh3n6-a25Rmnk_3"
  },
  "results": {
    "languages": [
      {
        "id": "8FvJPiWgD0sVDtTtAjaNf",
        "language": "200",
        "code": "{\n    \"id\": 53,\n    \"label\": \"Label1\",\n    \"color\": \"#2e86de\",\n    \"company\": 339\n}",
        "customLabel": ""
      },
      {
        "id": "SxinncXMLLo74s6ijrfPi",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "8FvJPiWgD0sVDtTtAjaNf"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "label",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": ""
      },
      {
        "name": "color",
        "kind": "optional",
        "type": "string",
        "description": "must be hexadecimal color value with the following format: #RRGGBB - Example: #2e86de\n",
        "": "must be hexadecimal color value with the following format: #RRGGBB - Example: #2e86de\n"
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "creates-a-customer-label-if-requesting-manager-has",
  "legacyHash": "qi-j4kp5xTngGjuD-Kkqc"
}
```
:::


[title] Update Customer Label
[path] Management API/Customer/Labels/

:::ApiMethodV2
```json
{
  "name": " Updates a customer label, if requesting manager has access permissions to it",
  "method": "PATCH",
  "url": "/api/v1/clabels/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "4uEdX2L_zVQVLCljy8QBx",
        "language": "json",
        "code": "{\n    \"label\": \"EditLabel2\",\n    \"color\": \"#2e86de\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "4uEdX2L_zVQVLCljy8QBx"
  },
  "results": {
    "languages": [
      {
        "id": "tA2AnN939DV_PcFcWXcl2",
        "language": "200",
        "code": "{\n    \"id\": 53,\n    \"label\": \"EditTest2\",\n    \"color\": \"#2e86de\",\n    \"company\": 339\n}",
        "customLabel": ""
      },
      {
        "id": "22mPANQkAg4bMsqbFXjZd",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "tA2AnN939DV_PcFcWXcl2"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "label",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "optional"
      },
      {
        "name": "color",
        "kind": "optional",
        "type": "string",
        "description": "must be hexadecimal color value with the following format: #RRGGBB - Example: #2e86de",
        "": "must be hexadecimal color value with the following format: #RRGGBB - Example: #2e86de"
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "updates-a-customer-label-if-requesting-manager-has",
  "legacyHash": "P4JNuOc7CRp7-KXsUPT3a"
}
```
:::




[title] Retrieve Customer Account
[path] Management API/Customer/Accounts/

:::ApiMethodV2
```json
{
  "name": "Retrieves a single customer account, if requesting manager has access permissions to it.",
  "method": "GET",
  "url": "/api/v1/customer-accounts/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "SgBThAJfGAhQgATbrwoEo",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "SgBThAJfGAhQgATbrwoEo"
  },
  "results": {
    "languages": [
      {
        "id": "axsJYSq4go7vKzoOW_SEu",
        "language": "200",
        "code": "{\n    \"id\": 811,\n    \"customers_count\": 0,\n    \"code\": \"tc4\",\n    \"name\": \"Test Customer Company 4\",\n    \"description\": \"\",\n    \"phone\": \"\",\n    \"address\": \"\",\n    \"email\": \"\",\n    \"cognito_user_pool_id\": \"\",\n    \"company\": 339\n}",
        "customLabel": ""
      },
      {
        "id": "cHjmTHjcJw-NlYBdAGX34",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "axsJYSq4go7vKzoOW_SEu"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "retrieves-a-single-customer-account-if-requesting",
  "legacyHash": "POacpmTqocUXWgOtf5Cpg"
}
```
:::


[title] Create Customer Account
[path] Management API/Customer/Accounts/

:::ApiMethodV2
```json
{
  "name": "Creates a customer account, if requesting manager has access permissions to it.",
  "method": "POST",
  "url": "/api/v1/customer-accounts/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "n5DOe1zPyWcjnag3k_5PC",
        "language": "json",
        "code": "{\n    \"name\": \"Test Customer Company 6\",\n    \"code\": \"tc6\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "n5DOe1zPyWcjnag3k_5PC"
  },
  "results": {
    "languages": [
      {
        "id": "VBcByNzY8-cJU0cfVRsGE",
        "language": "200",
        "code": "{\n    \"id\": 818,\n    \"code\": \"tc6\",\n    \"name\": \"Test Customer Company 6\",\n    \"description\": \"\",\n    \"phone\": \"\",\n    \"address\": \"\",\n    \"email\": \"\",\n    \"cognito_user_pool_id\": \"\",\n    \"company\": 339\n}",
        "customLabel": ""
      },
      {
        "id": "RzIPjrvXycjpfZXhbMCM3",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "VBcByNzY8-cJU0cfVRsGE"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "code",
        "kind": "required",
        "type": "string",
        "description": "must be unique",
        "": "must be unique"
      },
      {
        "name": "name",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "name"
      },
      {
        "name": "description",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "description"
      },
      {
        "name": "Phone",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "Phone"
      },
      {
        "name": "address",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "address"
      },
      {
        "name": "email",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "email"
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "creates-a-customer-account-if-requesting-manager-h",
  "legacyHash": "Gqm6yxMEkaZkTLHqiuWRH"
}
```
:::


[title] List Customer Account managers
[path] Management API/Customer/Accounts/

:::ApiMethodV2
```json
{
  "name": "Show all Customer Account managers.",
  "method": "GET",
  "url": "/api/v1/customer-accounts/{id}/managers/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "OtNGsCcRE7hsi-xYoYwWX",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "OtNGsCcRE7hsi-xYoYwWX"
  },
  "results": {
    "languages": [
      {
        "id": "N6SZbCTSzg5hNpC53y3kg",
        "language": "200",
        "code": "[\n    {\n        \"id\": 3420,\n        \"true_email\": \"example@gmail.com\",\n        \"is_initial_password\": true,\n        \"initial_password\": \"test1234\",\n        \"first_name\": \"First 1\",\n        \"last_name\": \"Last 1\",\n        \"phone_number\": \"\"\n    }\n]",
        "customLabel": ""
      },
      {
        "id": "pRLLHLlPG3D6EVrBDHpaz",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "N6SZbCTSzg5hNpC53y3kg"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "show-all-customer-account-managers",
  "legacyHash": "9h8GJkBD4jTN9FTAn1Sq9"
}
```
:::






[title] Making API Requests
[path] Management API/

All API calls are made to an API REST server, using GET, POST, PATCH or DELETE requests, depending on the API.

Body of each request, if any, should be plaintext, containing a valid JSON.

Each request needs to have a proper [**Management API Authorization**](docId\:aiksdoThZ3-fmk_NC0ePS) header.

### API Version:

All APIs should be used in their `/api/v1/` version.

:::hint{type="info"}
If not specifed endpoint has a maximum pagination limit of  **1000 items per request**
:::


[title] Delete Client
[path] Management API/Untitled/Customer/

:::ApiMethodV2
```json
{
  "name": "Delete customer OAuth client",
  "method": "DELETE",
  "url": "/api/v1/customers/{id}/client",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "y7p1h0F-eAbkZxck_2RG-",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "y7p1h0F-eAbkZxck_2RG-"
  },
  "results": {
    "languages": [
      {
        "id": "MVQ25SW50ApZtHi1d1B3H",
        "language": "200",
        "code": "Code: 200 OK",
        "customLabel": ""
      },
      {
        "id": "xvn6VvWpnyaJl0jTU_BPi",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "MVQ25SW50ApZtHi1d1B3H"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "delete-customer-oauth-client",
  "legacyHash": "Rftp6XGFFRpcDgqY-Ydf1"
}
```
:::


[title] Create Client
[path] Management API/Untitled/Customer/

:::ApiMethodV2
```json
{
  "name": "Create customer OAuth client ",
  "method": "POST",
  "url": "/api/v1/customers/{id}/client",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "r1uxcK_FtuyL9SGHyBF-q",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "r1uxcK_FtuyL9SGHyBF-q"
  },
  "results": {
    "languages": [
      {
        "id": "pNb-Ag5zvZhCxNegH3wL9",
        "language": "200",
        "code": "Code: 200 OK",
        "customLabel": ""
      },
      {
        "id": "1M0gQd7LM9w9Ou9Gh4tPA",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "pNb-Ag5zvZhCxNegH3wL9"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "create-customer-oauth-client",
  "legacyHash": "ek3wZBzsWPt3lbROl50kC"
}
```
:::

``

[title] Create Client
[path] Management API/Untitled/Customer Account/

:::ApiMethodV2
```json
{
  "name": "Create customer account OAuth client ",
  "method": "POST",
  "url": "/api/v1/customer-accounts/{id}/client",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "7K8ZYY9Fn3GP-FubLEGXQ",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "7K8ZYY9Fn3GP-FubLEGXQ"
  },
  "results": {
    "languages": [
      {
        "id": "shL7swIvy5qI0pGgGUFBp",
        "language": "200",
        "code": "Code: 200 OK",
        "customLabel": ""
      },
      {
        "id": "gAbr8AdvxUOfyxqD8Ymwe",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "shL7swIvy5qI0pGgGUFBp"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "create-customer-account-oauth-client",
  "legacyHash": "Q5JvfctAxlnJCng8IeDF0"
}
```
:::


[title] Delete Customer
[path] Management API/Customer/

:::ApiMethodV2
```json
{
  "name": "Deletes a single customer, if requesting manager has access permissions to it.",
  "method": "DELETE",
  "url": "/api/v1/customers/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "Pb3DXKyjEAVVg-y_3s9T8",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "Pb3DXKyjEAVVg-y_3s9T8"
  },
  "results": {
    "languages": [
      {
        "id": "4NFCzZMGw3rFnHKflDdG7",
        "language": "200",
        "code": "Code: 200 OK",
        "customLabel": ""
      },
      {
        "id": "Fm2R3sMoahUTJJrWKRoYA",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "4NFCzZMGw3rFnHKflDdG7"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "deletes-a-single-customer-if-requesting-manager-ha",
  "legacyHash": "3fHL7_dWqTy6LbaJXn0-p"
}
```
:::


[title] Merge Customers
[path] Management API/Customer/

Merges one customer into another, if requesting manager has access permissions to it.

:::hint{type="info"}
Updates customer on all orders from the customer provided in request body (`customer_to_merge_id`) to the customer provided in request URL and deletes the customer provided in request body (`customer_to_merge_id`).
:::

:::ApiMethodV2
```json
{
  "name": "Merges one customer into another, if requesting manager has access permissions to it.",
  "method": "POST",
  "url": "/api/v1/customers/{id}/merge/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "R3DaojXIjSFBVTMJinKE4",
        "language": "json",
        "code": "{\n    \"customer_to_merge_id\": 1013240\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "R3DaojXIjSFBVTMJinKE4"
  },
  "results": {
    "languages": [
      {
        "id": "y5fEoPuMdxBwp230r9MPo",
        "language": "200",
        "code": "{\n    \"message\": \"Merged.\"\n}",
        "customLabel": ""
      },
      {
        "id": "56vuAu0608R4pCDHB6kO4",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "y5fEoPuMdxBwp230r9MPo"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "merges-one-customer-into-another-if-requesting-man",
  "legacyHash": "OVG6IroGUaVX7nll7gLCm"
}
```
:::


[title] Export Customers
[path] Management API/Customer/

:::ApiMethodV2
```json
{
  "name": "Export multiple customers to csv , if requesting manager has access permissions to them.",
  "method": "GET",
  "url": "/api/v1/customers/export/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "vVMseWbGO7gyLE3c2YUtu",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "vVMseWbGO7gyLE3c2YUtu"
  },
  "results": {
    "languages": [
      {
        "id": "46LuWrhLL9VucYZDi6Qq2",
        "language": "200",
        "code": "customer_id,customer_first_name,customer_last_name,customer_email,customer_company_name,customer_phone,customer_reference,customer_address,customer_postcode,customer_state,customer_city,customer_country\n15354,Bruce,Willis,example1@email.com,ACME Inc.,,ref_user_1,2645 Black Bear Court,70501,Colorado,Lafayette,US\n15355,Harry,Potter,example2@email.com,Hogwarts,+385913334444,ref_user_2,2110 N. Williamston Rd.,70502,Michigan,Williamston,US",
        "customLabel": ""
      },
      {
        "id": "Eq6Gi4rc3ktUv-2gzAc6I",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "46LuWrhLL9VucYZDi6Qq2"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "export-multiple-customers-to-csv-if-requesting-man",
  "legacyHash": "2Idl70zNRpBYFM7y35BNo"
}
```
:::


[title] List Customers Import Results
[path] Management API/Customer/Import Results/

:::ApiMethodV2
```json
{
  "name": "Show all customers import results the requesting manager has access permissions to.",
  "method": "GET",
  "url": "/api/v1/customers-import-results/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "AUDCcIr6BE6D3vAqnqIjr",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "AUDCcIr6BE6D3vAqnqIjr"
  },
  "results": {
    "languages": [
      {
        "id": "f80wcsClA9FSF2Og29Xsh",
        "language": "200",
        "code": "{\n    \"count\": 9,\n    \"next\": null,\n    \"previous\": null,\n    \"results\": [\n        {\n            \"id\": 10,\n            \"file_name\": \"customers_example.csv\",\n            \"status\": \"success\",\n            \"created_at\": \"2021-03-15T10:01:03.456388Z\",\n            \"started_at\": \"2021-03-15T10:01:06.939592Z\",\n            \"finished_at\": \"2021-03-15T10:01:07.632023Z\",\n            \"result\": {\n                \"total_row_count\": 2,\n                \"valid_row_count\": 2,\n                \"invalid_rows\": [],\n                \"created_customers_count\": 0,\n                \"existed_customers_count\": 2\n            }\n        },\n        ...\n    ]\n}",
        "customLabel": ""
      },
      {
        "id": "XpojGgMZSfaV3p9X62SaF",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "f80wcsClA9FSF2Og29Xsh"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "show-all-customers-import-results-the-requesting-m",
  "legacyHash": "GL6vmCwW_vmPPiGGpEjCG"
}
```
:::

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on customer or related to the customer.

Possible filters:

- `status__iexact`
  - Choices: `pending`, `running`, `error`, `success`


[title] Delete Client
[path] Management API/Untitled/License/

:::ApiMethodV2
```json
{
  "name": "Delete license OAuth client",
  "method": "DELETE",
  "url": "/api/v1/licenses/{id}/client",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "Fe2zlYTu6hRfbokiDkDD9",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "Fe2zlYTu6hRfbokiDkDD9"
  },
  "results": {
    "languages": [
      {
        "id": "fQOmbGUG4m_LIPgsNzKJ4",
        "language": "200",
        "code": "Code: 200 OK",
        "customLabel": ""
      },
      {
        "id": "wbKHOZ9V9bONhqITKQUwC",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "fQOmbGUG4m_LIPgsNzKJ4"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "delete-license-oauth-client",
  "legacyHash": "TriDP8TnMfpkDMCQ1-C8X"
}
```
:::


[title] List Products in a Bundle
[path] Management API/Product/

:::ApiMethodV2
```json
{
  "name": "Show all products in a bundle the requesting manager has access permissions to.",
  "method": "GET",
  "url": "/api/v1/products/{id}/bundle/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "GgU9wCymdrLu8_qXlyxTS",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "GgU9wCymdrLu8_qXlyxTS"
  },
  "results": {
    "languages": [
      {
        "id": "s-tP6hc9nbx0b1eZ6DNer",
        "language": "200",
        "code": "[\n    {\n        \"id\": 1584723961091260,\n        \"short_code\": \"bugs\",\n        \"product_name\": \"bugs\"\n    }\n    ...\n]",
        "customLabel": ""
      },
      {
        "id": "26m4n8wism-0sChM1dEHa",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "s-tP6hc9nbx0b1eZ6DNer"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "show-all-products-in-a-bundle-the-requesting-manag",
  "legacyHash": "HfexQBLrksPLPb7VMxbF-"
}
```
:::


[title] List Product Custom Fields
[path] Management API/Product/Custom Fields/

:::ApiMethodV2
```json
{
  "name": "Show all product custom fields the requesting manager has access permissions to.",
  "method": "GET",
  "url": "/api/v1/product-custom-fields/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "b0xj3F46234ncp6cj0d3f",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "b0xj3F46234ncp6cj0d3f"
  },
  "results": {
    "languages": [
      {
        "id": "aTMf1--aFpAngFFPMIUgA",
        "language": "200",
        "code": "{\n    \"count\": 3,\n    \"next\": null,\n    \"previous\": null,\n    \"results\": [\n        {\n            \"id\": 66,\n            \"product_custom_field_enums\": [],\n            \"name\": \"cf1\",\n            \"data_type\": null,\n            \"default_value\": \"1\",\n            \"description\": null,\n            \"product\": 1584723961091260\n        }\n        ...\n    ]\n}",
        "customLabel": ""
      },
      {
        "id": "3PthBJ1JJ9aRMWo8_HjeX",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "aTMf1--aFpAngFFPMIUgA"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "show-all-product-custom-fields-the-requesting-mana",
  "legacyHash": "Z37WsUV9DKP4xmBlaKx3O"
}
```
:::

### Query Parameters:

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on product custom field or related to the product custom field.

Possible filters:

- `product`

[title] Retrieve Product custom field enumeration
[path] Management API/Product/Custom Field Enumerations/

:::ApiMethodV2
```json
{
  "name": "Retrieve a single product custom field enumeration if requesting manager has access permissions to it.",
  "method": "GET",
  "url": " /api/v1/product-custom-field-enums/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "NsH70ryCTWFlAJ4YFFCgT",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "NsH70ryCTWFlAJ4YFFCgT"
  },
  "results": {
    "languages": [
      {
        "id": "2VNJZCMZxwfXm62y8jvcG",
        "language": "200",
        "code": "{\n    \"id\": 1,\n    \"value\": \"vv1\",\n    \"product_custom_field\": 69\n}",
        "customLabel": ""
      },
      {
        "id": "3GcsLtZWCVCfVPfHdKs-v",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "2VNJZCMZxwfXm62y8jvcG"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "retrieve-a-single-product-custom-field-enumeration",
  "legacyHash": "A12BK8oTWXmqeTr8bzGER"
}
```
:::


[title] Create Product custom field enumeration
[path] Management API/Product/Custom Field Enumerations/

:::ApiMethodV2
```json
{
  "name": "Creates a product custom field enumeration if requesting manager has access permissions to it.",
  "method": "POST",
  "url": "/api/v1/product-custom-field-enums/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "yi51PNVPavB6bzaq08zAo",
        "language": "json",
        "code": "{\n    \"value\": \"vv2\",\n    \"product_custom_field\": 10003\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "yi51PNVPavB6bzaq08zAo"
  },
  "results": {
    "languages": [
      {
        "id": "Vuwr7EMLNcV3ptTJ2lgQH",
        "language": "200",
        "code": "{\n    \"id\": 1,\n    \"value\": \"vv2\",\n    \"product_custom_field\": 10003\n}",
        "customLabel": ""
      },
      {
        "id": "tn2Cb4SXjOTw0mFwUPYyW",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "Vuwr7EMLNcV3ptTJ2lgQH"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "value",
        "kind": "required",
        "type": "string",
        "description": "",
        "": ""
      },
      {
        "name": "product_custom_field",
        "kind": "required",
        "type": "string",
        "description": "",
        "": "required"
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "creates-a-product-custom-field-enumeration-if-requ",
  "legacyHash": "oinsOAXvZ4O82dvV4q3a3"
}
```
:::


[title] Update Product custom field enumeration
[path] Management API/Product/Custom Field Enumerations/

:::ApiMethodV2
```json
{
  "name": "Updates a product custom field enumeration if requesting manager has access permissions to it.",
  "method": "PATCH",
  "url": "/api/v1/product-custom-field-enums/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "EjbgmATkZbNIdupisb3P-",
        "language": "json",
        "code": "{\n    \"value\": \"f4\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "EjbgmATkZbNIdupisb3P-"
  },
  "results": {
    "languages": [
      {
        "id": "uGCXzCHawWXvCf9oOOdru",
        "language": "200",
        "code": "{\n    \"id\": 1,\n    \"value\": \"f4\",\n    \"product_custom_field\": 69\n}",
        "customLabel": ""
      },
      {
        "id": "PanR2r5htkE9bZUubCy65",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "uGCXzCHawWXvCf9oOOdru"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "value ",
        "kind": "required",
        "type": "string",
        "description": "",
        "": ""
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "updates-a-product-custom-field-enumeration-if-requ",
  "legacyHash": "znYRnyM3EsOaTkSWYi9cg"
}
```
:::


[title] Get Product Details
[path] License API/Products/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/product_details",
  "name": "/api/v4/product_details",
  "method": "GET",
  "request": {
    "pathParameters": [],
    "queryParameters": [
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "name": "include_latest_version",
        "kind": "optional",
        "type": "Boolean",
        "description": "Includes details on latest installation file (default: false)",
        "children": []
      },
      {
        "name": "include_custom_fields",
        "kind": "optional",
        "type": "Boolean",
        "description": " Include product custom fields definition (default: false)",
        "children": []
      },
      {
        "name": "env",
        "kind": "optional",
        "type": "string",
        "description": "Filter products by environment string (as defined by installation file \"environment\")",
        "children": []
      }
    ],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "QLX3IFr3FPKeqNnhkuAXk",
        "code": "{\n    \"product_id\": 1683881296184003,\n    \"product_name\": \"p\",\n    \"short_code\": \"p\",\n    \"allow_trial\": false,\n    \"trial_days\": 0,\n    \"authorization_method\": \"license-key\",\n    \"allow_overages\": false,\n    \"max_overages\": 0,\n    \"prevent_vm\": false,\n    \"floating_timeout\": 5,\n    \"metadata\": {}\n}",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "r7pnaNGfLVC8RZ1IcgRV8",
        "code": "{\n    \"unknown_product\": \"Provided product code x was not found.\"\n    \"missing_headers\": \"must have required property 'authorization'\"\n    \"missing_parameters\": \"missing parameters\"\n  }",
        "language": "404",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "QLX3IFr3FPKeqNnhkuAXk"
  },
  "examples": {
    "languages": [
      {
        "id": "746PImYZYs67XZTCZunvc",
        "language": "curl",
        "code": "curl --location --request GET '/api/v4/product_details?product=string' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string'",
        "customLabel": ""
      },
      {
        "id": "k8bCiwtmATN4gT61DmQ0e",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'GET',\n   'url': '/api/v4/product_details?product=string',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   }\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "Oc5yC_zT4RO-cM_DaZYO_",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar requestOptions = {\n   method: 'GET',\n   headers: myHeaders,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/product_details?product=string\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "KK_fnENt8XuSln2IJnVBR",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/product_details?product=string\"\n\npayload={}\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"GET\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "6MWs64fzwnjA50ddEnOT7",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/product_details?product=string\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "KK_fnENt8XuSln2IJnVBR"
  },
  "description": "Returns all metadata for a product",
  "currentNewParameter": {
    "label": "Query Parameter",
    "value": "queryParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4productdetails",
  "legacyHash": "N8J7DFnfZkfw2yRXqPLW-"
}
```
:::

## Schema

### Request Query Parameters

:::CodeblockTabs
```typescript
type ProductDetailsRequestParameters = {
  
  // required parameters:
  product: string,
  
  // required for key-based products:
  license_key: string
  
  // required for user-based products:
  username: string
  
  // optional parameters:
  license_id?: string | undefined,
  include_latest_version?: boolean | undefined,
  include_custom_fields?: boolean | undefined,
}
```

JSON Schema

```json
```
:::

### Response Body

:::CodeblockTabs
```typescript
type ProductDetailsResponseBody = {
    product_id: number;
    product_name: string;
    short_code: string;
    authorization_method: "license-key" | "user";
    floating_timeout: number;
    max_overages: number;
    trial_days: number;
    allow_overages: boolean;
    allow_trial: boolean;
    prevent_vm: boolean;
    metadata: JSON;
    
    // this property is only present if "include_custom_fields" query param is true
    custom_fields?: {
        id: number;
        name: string;
        default_value: string;
    }[] | undefined;
    
    // this property is only present if "include_latest_version" query param is true
    latest_version?: {
        version: string | null;
        environment: string | null;
        hash_md5: string | null;
        eula_link: string | null;
        release_notes_link: string | null;
        size: string | null;
        requires_version: string | null;
        channel: string | null;
        release_date: string | null;
        id: number;
        product_id: number;
        enabled: boolean;
        full_link: string | null;
        filename: string | null;
        created_at: string; // Date string in full ISO 8601 format, e.g. "2024-09-27T23:30:48.016Z"
        updated_at: string; // Date string in full ISO 8601 format, e.g. "2024-09-27T23:30:48.016Z"
    } | undefined;
}
```

JSON Schema

```json
```
:::

:::hint{type="info"}
If product **does not** have a version defined, it will return `null`
:::

:::hint{type="info"}
If product **does not** have any custom fields defined, it will return an empty array
:::

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**missing\_headers** (400): Some headers are missing
:::

:::BlockQuote
**missing\_parameters** (400): Some parameters are missing in the request: \{ params }
:::


[title] Get Client
[path] Management API/Untitled/License/

:::ApiMethodV2
```json
{
  "name": "Show license OAuth client information",
  "method": "GET",
  "url": "/api/v1/licenses/{id}/client",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "WP0AlcTntmzViL4b55sFc",
        "language": "json",
        "code": "{\n    \"id\": \"34d37bc0-95dc-4186-9b2b-d1988b733bdf\",\n    \"clientId\": \"name\",\n    \"name\": \"name\",\n    \"description\": \"\",\n    \"rootUrl\": \"https://api.licensespring.com\",\n    \"adminUrl\": \"https://api.licensespring.com\",\n    \"baseUrl\": \"https://api.licensespring.com\",\n    \"surrogateAuthRequired\": false,\n    \"enabled\": true,\n    \"alwaysDisplayInConsole\": false,\n    \"clientAuthenticatorType\": \"client-secret\",\n    \"secret\": \"thisissecret\",\n    \"redirectUris\": [\n        \"https://api.licensespring.com/*\"\n    ],\n    \"webOrigins\": [\n        \"+\"\n    ],\n    \"notBefore\": 0,\n    \"bearerOnly\": false,\n    \"consentRequired\": false,\n    \"standardFlowEnabled\": true,\n    \"implicitFlowEnabled\": true,\n    \"directAccessGrantsEnabled\": true,\n    \"serviceAccountsEnabled\": true,\n    \"authorizationServicesEnabled\": true,\n    \"publicClient\": false,\n    \"frontchannelLogout\": true,\n    \"protocol\": \"openid-connect\",\n    \"attributes\": {\n        \"realm_client\": \"false\",\n        \"oidc.ciba.grant.enabled\": \"false\",\n        \"client.secret.creation.time\": \"1756205819\",\n        \"backchannel.logout.session.required\": \"true\",\n        \"post.logout.redirect.uris\": \"+\",\n        \"oauth2.device.authorization.grant.enabled\": \"true\",\n        \"backchannel.logout.revoke.offline.tokens\": \"false\"\n    },\n    \"authenticationFlowBindingOverrides\": {},\n    \"fullScopeAllowed\": true,\n    \"nodeReRegistrationTimeout\": -1,\n    \"protocolMappers\": [\n        {\n            \"id\": \"18f99bd4-29cd-4424-9cb0-59a4aae2bc76\",\n            \"name\": \"Client ID\",\n            \"protocol\": \"openid-connect\",\n            \"protocolMapper\": \"oidc-usersessionmodel-note-mapper\",\n            \"consentRequired\": false,\n            \"config\": {\n                \"user.session.note\": \"client_id\",\n                \"id.token.claim\": \"true\",\n                \"introspection.token.claim\": \"true\",\n                \"access.token.claim\": \"true\",\n                \"claim.name\": \"client_id\",\n                \"jsonType.label\": \"String\"\n            }\n        },\n        {\n            \"id\": \"bded44dc-1446-4906-86d2-9d57db208857\",\n            \"name\": \"Client IP Address\",\n            \"protocol\": \"openid-connect\",\n            \"protocolMapper\": \"oidc-usersessionmodel-note-mapper\",\n            \"consentRequired\": false,\n            \"config\": {\n                \"user.session.note\": \"clientAddress\",\n                \"id.token.claim\": \"true\",\n                \"introspection.token.claim\": \"true\",\n                \"access.token.claim\": \"true\",\n                \"claim.name\": \"clientAddress\",\n                \"jsonType.label\": \"String\"\n            }\n        },\n        {\n            \"id\": \"e8f32f07-c323-4ce3-a046-82b4b679bf2e\",\n            \"name\": \"Client Host\",\n            \"protocol\": \"openid-connect\",\n            \"protocolMapper\": \"oidc-usersessionmodel-note-mapper\",\n            \"consentRequired\": false,\n            \"config\": {\n                \"user.session.note\": \"clientHost\",\n                \"id.token.claim\": \"true\",\n                \"introspection.token.claim\": \"true\",\n                \"access.token.claim\": \"true\",\n                \"claim.name\": \"clientHost\",\n                \"jsonType.label\": \"String\"\n            }\n        }\n    ],\n    \"defaultClientScopes\": [\n        \"web-origins\",\n        \"acr\",\n        \"profile\",\n        \"roles\",\n        \"basic\",\n        \"email\"\n    ],\n    \"optionalClientScopes\": [\n        \"address\",\n        \"phone\",\n        \"offline_access\",\n        \"microprofile-jwt\"\n    ],\n    \"access\": {\n        \"view\": true,\n        \"configure\": true,\n        \"manage\": true\n    }\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "WP0AlcTntmzViL4b55sFc"
  },
  "results": {
    "languages": [
      {
        "id": "tvX-sUNw5mQMrEsW38JDw",
        "language": "200",
        "code": "Code: 200 OK",
        "customLabel": ""
      },
      {
        "id": "nFdMg2HCHiLxbXZvfGu-k",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "tvX-sUNw5mQMrEsW38JDw"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "show-license-oauth-client-information",
  "legacyHash": "lqirJ_IfKzoN0J1BvdJ2U"
}
```
:::


[title] Import Product Features From CSV
[path] Management API/Product/Features/

:::hint{type="warning"}
Ensure that all text fields in your CSV use **ASCII characters**. Non-ASCII characters (such as “ä”, “ñ”, or other special symbols) can cause import errors. To avoid issues, remove or replace these characters before uploading your file.
:::

:::ApiMethodV2
```json
{
  "name": "Imports product features from CSV, if requesting manager has access permissions to it.",
  "method": "POST",
  "url": "/api/v1/product-features/import_from_csv/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "cVkBNeTSjCHH3I0NWdIuK",
        "language": "null",
        "code": "product__short_code,code,name\nLKP1,C123,A\nLKP1,C456,B",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "cVkBNeTSjCHH3I0NWdIuK"
  },
  "results": {
    "languages": [
      {
        "id": "8w1J4_HXTeLrmpu6Oqixt",
        "language": "200",
        "code": "{\n    \"job_id\": 10\n}",
        "customLabel": ""
      },
      {
        "id": "zScCpvwnk5k1zKlkOXi1z",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "8w1J4_HXTeLrmpu6Oqixt"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "imports-product-features-from-csv-if-requesting-ma",
  "legacyHash": "CZpvOiFD6ZijDTeKYtYG-"
}
```
:::

### Content-Type

Required `Content-Type` is `multipart/form-data` with the following single key value pair:

- Key: `file`
- Value: `{csv file from which to import}`

### Required CSV Headers

- `name`
- `code`

### Possible CSV Headers

- `code`– String
- `product__short_code`– String
- `feature_type` - String
  - Choices: `activation`, `consumption`
- `max_consumption` - Integer
- `allow_overages` - Boolean
- `max_overages` - Integer
- `reset_consumption` - Boolean
- `consumption_period` - String
  - Choices: `daily`, `weekly`, `monthly`, `annually`
- `is_floating` - Boolean
- `is_floating_cloud` -Boolean
- `floating_users` - Integer
- `floating_timeout` - Integer

:::hint{type="info"}
`job_id` from response can be used to query the import result.
:::


[title] Delete Product Custom Field
[path] Management API/Product/Custom Fields/

:::ApiMethodV2
```json
{
  "name": "Delete a single product custom field, if requesting manager has access permissions to it.",
  "method": "DELETE",
  "url": "/api/v1/product-custom-fields/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "m61iLjseWtmKJRIjiNTKY",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "m61iLjseWtmKJRIjiNTKY"
  },
  "results": {
    "languages": [
      {
        "id": "LW782UsyaD-avqrb5RvF3",
        "language": "200",
        "code": "Code: 200 OK",
        "customLabel": ""
      },
      {
        "id": "fHoeINaO4FiCcR6heV2PZ",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "LW782UsyaD-avqrb5RvF3"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "delete-a-single-product-custom-field-if-requesting",
  "legacyHash": "ol7zBTbWso7eCquSOWA8N"
}
```
:::


[title] /product-features/
[path] Management API/Product/


[title] Retrieve Customer Label
[path] Management API/Customer/Labels/

:::ApiMethodV2
```json
{
  "name": "Retrieve a single customer label, if requesting manager has access permissions to it.",
  "method": "GET",
  "url": "/api/v1/clabels/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "smhvmswFzfxLl4oJENo2Y",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "smhvmswFzfxLl4oJENo2Y"
  },
  "results": {
    "languages": [
      {
        "id": "uHPfqXJIVrRqO4PGRkkrK",
        "language": "200",
        "code": "\n    \"id\": 1,\n    \"label\": \"Internal\",\n    \"color\": \"#2e86de\",\n    \"company\": null\n}",
        "customLabel": ""
      },
      {
        "id": "RyZITXFKRZiV9mAatiegF",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "uHPfqXJIVrRqO4PGRkkrK"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "retrieve-a-single-customer-label-if-requesting-man",
  "legacyHash": "CDjifUkawIvcViXzzBXtN"
}
```
:::




[title] List Bundles for a Product
[path] Management API/Product/

:::ApiMethodV2
```json
{
  "name": "Show all bundles for a product the requesting manager has access permissions to.",
  "method": "GET",
  "url": "/api/v1/products/{id}/in_bundle/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "MC7XHzVmdea-jiqlRjIfQ",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "MC7XHzVmdea-jiqlRjIfQ"
  },
  "results": {
    "languages": [
      {
        "id": "7rZWua9Fh9LtDzxCaLcn6",
        "language": "200",
        "code": "[\n    {\n        \"id\": 1586066454419482,\n        \"short_code\": \"bt1\",\n        \"product_name\": \"Bundle test 1\"\n    },\n    ...\n]",
        "customLabel": ""
      },
      {
        "id": "CK2NwPWBrV-XQBHHVgr_X",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "7rZWua9Fh9LtDzxCaLcn6"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "show-all-bundles-for-a-product-the-requesting-mana",
  "legacyHash": "0DHkhBNODO6tgv-kfpjzj"
}
```
:::


[title] Create Product Custom Field
[path] Management API/Product/Custom Fields/

:::ApiMethodV2
```json
{
  "name": "Creates a product custom field, if requesting manager has access permissions to it.",
  "method": "POST",
  "url": "/api/v1/product-custom-fields/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "PnDRMltIkaWDFEOSUSP2P",
        "language": "json",
        "code": "{\n    \"name\": \"cf2\",\n    \"default_value\": \"2\",\n    \"product\": 1584723961091260\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "PnDRMltIkaWDFEOSUSP2P"
  },
  "results": {
    "languages": [
      {
        "id": "GEXWewn-PSiVkP5wXbfLn",
        "language": "200",
        "code": "{\n    \"id\": 67,\n    \"name\": \"cf2\",\n    \"data_type\": null,\n    \"default_value\": \"2\",\n    \"description\": null,\n    \"product\": 1584723961091260\n}",
        "customLabel": ""
      },
      {
        "id": "JcKgYqxSD47e9qq5wMSif",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "GEXWewn-PSiVkP5wXbfLn"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "name",
        "kind": "required",
        "type": "string",
        "description": "",
        "": ""
      },
      {
        "name": "default_value",
        "kind": "required",
        "type": "string",
        "description": "",
        "": "required"
      },
      {
        "name": "product",
        "kind": "required",
        "type": "integer",
        "description": "",
        "": "required"
      },
      {
        "name": "data_type",
        "kind": "optional",
        "type": "string",
        "description": "Choices: number, text, date/time",
        "": "Choices: number, text, date/time"
      },
      {
        "name": "description",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "description"
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "creates-a-product-custom-field-if-requesting-manag",
  "legacyHash": "HZWDZNw4OQjr_CR0m0xG7"
}
```
:::


[title] Floating
[path] License API/



In the realm of software license management, a floating license offers the flexibility for multiple users to access a software application simultaneously, subject to a specified maximum limit of active users. This concurrent licensing model is enhanced by features that allow users to "borrow" a license for offline use and "release" it back to the available pool, optimizing resource allocation and usage.

## Introduction

or an in-depth explanation of the implementation and management of floating licenses within your software, including configuration details and API interactions, please read our comprehensive guide here: [**Floating Licenses**](https://docs.licensespring.com/license-entitlements/floating-licenses), [**Floating features**](https://docs.licensespring.com/license-api/floating/feature/release)

## API

If you're specifically looking for detailed information on how to utilize the API for managing floating features, including check-in and release processes, you can access the full license API documentation here: [**Floating Licenses**](https://docs.licensespring.com/license-entitlements/floating-licenses), [**Floating features**](https://docs.licensespring.com/license-api/floating/feature/release)

[title] Retrieve Product Custom Field
[path] Management API/Product/Custom Fields/

:::ApiMethodV2
```json
{
  "name": "Retrieve a single product custom field, if requesting manager has access permissions to it.",
  "method": "GET",
  "url": "/api/v1/product-custom-fields/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "h664nyeFPcm6CgdUxNRk_",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "h664nyeFPcm6CgdUxNRk_"
  },
  "results": {
    "languages": [
      {
        "id": "B2vb9Eqqfi0B6St8emiE8",
        "language": "200",
        "code": "{\n    \"id\": 66,\n    \"product_custom_field_enums\": [],\n    \"name\": \"cf1\",\n    \"data_type\": null,\n    \"default_value\": \"1\",\n    \"description\": null,\n    \"product\": 1584723961091260\n}",
        "customLabel": ""
      },
      {
        "id": "7MxRkBFJK96VXT17eNwRj",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "B2vb9Eqqfi0B6St8emiE8"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "retrieve-a-single-product-custom-field-if-requesti",
  "legacyHash": "pt8SxzOevROxuj1pJheWy"
}
```
:::


[title] Retrieve Customers Import Result
[path] Management API/Customer/Import Results/

:::ApiMethodV2
```json
{
  "name": "Retrieve a single customers import result, if requesting manager has access permissions to it.",
  "method": "GET",
  "url": "/api/v1/customers-import-results/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "8IwfHDOMs2VcxGGnkpUbU",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "8IwfHDOMs2VcxGGnkpUbU"
  },
  "results": {
    "languages": [
      {
        "id": "n0v_SDJd28rEVLpMIauMk",
        "language": "200",
        "code": "{\n    \"id\": 9,\n    \"file_name\": \"customers_example.csv\",\n    \"status\": \"success\",\n    \"created_at\": \"2021-03-15T09:27:30.970371Z\",\n    \"started_at\": \"2021-03-15T09:29:54.836154Z\",\n    \"finished_at\": \"2021-03-15T09:29:55.417980Z\",\n    \"result\": {\n        \"total_row_count\": 2,\n        \"valid_row_count\": 2,\n        \"invalid_rows\": [],\n        \"created_customers_count\": 2,\n        \"existed_customers_count\": 0\n    }\n}",
        "customLabel": ""
      },
      {
        "id": "y6ozGmnib8H45GhsWYYhQ",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "n0v_SDJd28rEVLpMIauMk"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "retrieve-a-single-customers-import-result-if-reque",
  "legacyHash": "csZP_FD4VUL46UPV5MJjl"
}
```
:::






[title] Change Password
[path] License API/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/change_password",
  "name": "/api/v4/change_password",
  "method": "POST",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [
      {
        "kind": "required",
        "name": "username",
        "type": "String",
        "children": [],
        "description": ""
      },
      {
        "kind": "required",
        "name": "password",
        "type": "string",
        "children": [],
        "description": ""
      },
      {
        "name": "new_password",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      }
    ],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "es8g1cuKJMbNPiIVt9VoF",
        "code": "password_changed",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "7eyIlKSv2QgJcowEsDZ-2",
        "code": "{\n    \"unknown_product\": \"Provided product was not found\",\n    \"license_not_found\": \"License with the provided license user not found\",\n    \"license_not_enabled\": \"The license is not enabled\",\n    \"blacklisted\": \"This device is blacklisted\",\n    \"device_not_found\": \"An active device matching the hardware_id not found.\",\n\n    \ndodaj jos",
        "language": "400",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "es8g1cuKJMbNPiIVt9VoF"
  },
  "examples": {
    "languages": [
      {
        "id": "FRH06Ud70ZwhCXYYNOyXs",
        "language": "curl",
        "code": "curl --location --request POST '/api/v4/change_password' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string' \\\n--data-raw '{\"username\":\"String\",\"password\":\"string\",\"new_password\":\"string\"}'",
        "customLabel": ""
      },
      {
        "id": "HwQF488PLEPm5y8gB_i6L",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'POST',\n   'url': '/api/v4/change_password',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   },\n   body: '{\"username\":\"String\",\"password\":\"string\",\"new_password\":\"string\"}'\n\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "R2mQsWYqxxPpzQ_vDKBKW",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar raw = \"{\\\"username\\\":\\\"String\\\",\\\"password\\\":\\\"string\\\",\\\"new_password\\\":\\\"string\\\"}\";\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/change_password\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "w7aQEaxxclXA_0mgTIsIz",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/change_password\"\n\npayload = \"{\\\"username\\\":\\\"String\\\",\\\"password\\\":\\\"string\\\",\\\"new_password\\\":\\\"string\\\"}\"\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "wC4Evf4x0TR9e8NoXxaLk",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/change_password\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\nrequest.body = \"{\\\"username\\\":\\\"String\\\",\\\"password\\\":\\\"string\\\",\\\"new_password\\\":\\\"string\\\"}\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "FRH06Ud70ZwhCXYYNOyXs"
  },
  "description": "Changes a license user's password\n",
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4changepassword",
  "legacyHash": "qAgfesKV8lHL1RYa1ODTa"
}
```
:::

## Schema

### Request Body

:::CodeblockTabs
```typescript
type ChangePasswordRequestBody = {
  username: string,
  password: string,
  new_password: string,
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "username": { "type": "string" },
    "password": { "type": "string" },
    "new_password": { "type": "string" }
  },
  "required": ["username", "password", "new_password"],
  "additionalProperties": false
}
```
:::

### Response Body

:::CodeblockTabs
```typescript
type ChangePasswordResponseBody = 'password_changed'
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "string",
}
```
:::

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

**change\_password\_not\_allowed** (400): Change password not allowed for the company

**missing\_headers** (400): Some headers are missing

**missing\_parameters** (400): Some parameters are missing in the request: \{ params }.

[title] Update Customer Account
[path] Management API/Customer/Accounts/

:::ApiMethodV2
```json
{
  "name": "Updates a customer account, if requesting manager has access permissions to it.",
  "method": "PATCH",
  "url": "/api/v1/customer-accounts/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "FdBqSpzK8xQ4ahjhlMX4I",
        "language": "json",
        "code": "{\n    \"description\": \"test desc\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "FdBqSpzK8xQ4ahjhlMX4I"
  },
  "results": {
    "languages": [
      {
        "id": "iDOSot7TZiAevSIeqhHU1",
        "language": "200",
        "code": "{\n    \"id\": 818,\n    \"customers_count\": 0,\n    \"code\": \"tc6\",\n    \"name\": \"Test Customer Company 6\",\n    \"description\": \"test desc\",\n    \"phone\": \"\",\n    \"address\": \"\",\n    \"email\": \"\",\n    \"cognito_user_pool_id\": \"\",\n    \"company\": 339\n}",
        "customLabel": ""
      },
      {
        "id": "wWBwoVa87lli_3YeOEVlf",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "iDOSot7TZiAevSIeqhHU1"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "name",
        "kind": "optional",
        "type": "string",
        "description": "ID of the cake to get",
        "": "optional"
      },
      {
        "name": "description",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "description"
      },
      {
        "name": "phone",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "phone"
      },
      {
        "name": "address",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "address"
      },
      {
        "name": "email",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "email"
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "updates-a-customer-account-if-requesting-manager-h",
  "legacyHash": "Zm1rQbdKltqa-EpCgG0ZX"
}
```
:::





[title] Get Client
[path] Management API/Untitled/Customer Account/

:::ApiMethodV2
```json
{
  "name": "Show customer account OAuth client information",
  "method": "GET",
  "url": "/api/v1/customer-accounts/{id}/client",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "VKFWp0nFFC5iIL7_mHI6b",
        "language": "json",
        "code": "{\n    \"id\": \"4f50e517-03f5-41fb-8b23-94f807414cab\",\n    \"clientId\": \"auth-customeraccount-1219\",\n    \"name\": \"auth-customeraccount-1219\",\n    \"description\": \"\",\n    \"rootUrl\": \"https://api.licensespring.com\",\n    \"adminUrl\": \"https://api.licensespring.com\",\n    \"baseUrl\": \"https://api.licensespring.com\",\n    \"surrogateAuthRequired\": false,\n    \"enabled\": true,\n    \"alwaysDisplayInConsole\": false,\n    \"clientAuthenticatorType\": \"client-secret\",\n    \"secret\": \"secret\",\n    \"redirectUris\": [\n        \"https://api.licensespring.com/*\"\n    ],\n    \"webOrigins\": [\n        \"+\"\n    ],\n    \"notBefore\": 0,\n    \"bearerOnly\": false,\n    \"consentRequired\": false,\n    \"standardFlowEnabled\": true,\n    \"implicitFlowEnabled\": true,\n    \"directAccessGrantsEnabled\": true,\n    \"serviceAccountsEnabled\": true,\n    \"authorizationServicesEnabled\": true,\n    \"publicClient\": false,\n    \"frontchannelLogout\": true,\n    \"protocol\": \"openid-connect\",\n    \"attributes\": {\n        \"client.secret.rotated.creation.time\": \"1753853304\",\n        \"client.secret.creation.time\": \"1753853304\",\n        \"SECRET_ROTATED_EXPIRATION_PERIOD\": \"604800\",\n        \"client.secret.expiration.time\": \"1756445304\",\n        \"post.logout.redirect.uris\": \"+\",\n        \"oauth2.device.authorization.grant.enabled\": \"true\",\n        \"backchannel.logout.revoke.offline.tokens\": \"false\",\n        \"client.secret.rotated.expiration.time\": \"1754458104\",\n        \"SECRET_REMAINING_ROTATION_PERIOD\": \"172800\",\n        \"realm_client\": \"false\",\n        \"oidc.ciba.grant.enabled\": \"false\",\n        \"SECRET_EXPIRATION_PERIOD\": \"2592000\",\n        \"backchannel.logout.session.required\": \"true\",\n        \"client.secret.rotated\": \"zv1hKzrgX8IBglJfEkt0UYQX3pJ5RrEO\"\n    },\n    \"authenticationFlowBindingOverrides\": {},\n    \"fullScopeAllowed\": true,\n    \"nodeReRegistrationTimeout\": -1,\n    \"protocolMappers\": [\n        {\n            \"id\": \"05421ca8-9c76-453c-a06b-0f5fc68db03e\",\n            \"name\": \"Client Host\",\n            \"protocol\": \"openid-connect\",\n            \"protocolMapper\": \"oidc-usersessionmodel-note-mapper\",\n            \"consentRequired\": false,\n            \"config\": {\n                \"user.session.note\": \"clientHost\",\n                \"id.token.claim\": \"true\",\n                \"introspection.token.claim\": \"true\",\n                \"access.token.claim\": \"true\",\n                \"claim.name\": \"clientHost\",\n                \"jsonType.label\": \"String\"\n            }\n        },\n        {\n            \"id\": \"e9877f79-45c4-4564-8238-bf2961a36e21\",\n            \"name\": \"Client IP Address\",\n            \"protocol\": \"openid-connect\",\n            \"protocolMapper\": \"oidc-usersessionmodel-note-mapper\",\n            \"consentRequired\": false,\n            \"config\": {\n                \"user.session.note\": \"clientAddress\",\n                \"id.token.claim\": \"true\",\n                \"introspection.token.claim\": \"true\",\n                \"access.token.claim\": \"true\",\n                \"claim.name\": \"clientAddress\",\n                \"jsonType.label\": \"String\"\n            }\n        },\n        {\n            \"id\": \"a7d416a2-20c2-4788-8864-7fa502fd4d51\",\n            \"name\": \"Client ID\",\n            \"protocol\": \"openid-connect\",\n            \"protocolMapper\": \"oidc-usersessionmodel-note-mapper\",\n            \"consentRequired\": false,\n            \"config\": {\n                \"user.session.note\": \"client_id\",\n                \"id.token.claim\": \"true\",\n                \"introspection.token.claim\": \"true\",\n                \"access.token.claim\": \"true\",\n                \"claim.name\": \"client_id\",\n                \"jsonType.label\": \"String\"\n            }\n        }\n    ],\n    \"defaultClientScopes\": [\n        \"web-origins\",\n        \"acr\",\n        \"profile\",\n        \"roles\",\n        \"basic\",\n        \"email\"\n    ],\n    \"optionalClientScopes\": [\n        \"address\",\n        \"phone\",\n        \"offline_access\",\n        \"microprofile-jwt\"\n    ],\n    \"access\": {\n        \"view\": true,\n        \"configure\": true,\n        \"manage\": true\n    }\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "VKFWp0nFFC5iIL7_mHI6b"
  },
  "results": {
    "languages": [
      {
        "id": "2k65Jjl5kwtsA6PtdkzHW",
        "language": "200",
        "code": "Code: 200 OK",
        "customLabel": ""
      },
      {
        "id": "-GHJYa0s1ANUwpIGm2yUU",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "2k65Jjl5kwtsA6PtdkzHW"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "show-customer-account-oauth-client-information",
  "legacyHash": "M-ANx8akKvfb0mpHshQS4"
}
```
:::


[title] Create Client
[path] Management API/Untitled/License/

:::ApiMethodV2
```json
{
  "name": "Create license OAuth client",
  "method": "POST",
  "url": "/api/v1/licenses/{id}/client",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "DS5uQiBwUukFeafW7_1E2",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "DS5uQiBwUukFeafW7_1E2"
  },
  "results": {
    "languages": [
      {
        "id": "hzlm5Ms4498xxT1sviWcB",
        "language": "200",
        "code": "Code: 200 OK",
        "customLabel": ""
      },
      {
        "id": "BY4zZCYGa0sQSrczbK7qD",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "hzlm5Ms4498xxT1sviWcB"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "create-license-oauth-client",
  "legacyHash": "OgQdQ212VkXmHMDEcSfWX"
}
```
:::


[title] Retrieve Product
[path] Management API/Product/

:::ApiMethodV2
```json
{
  "name": "Retrieve a single product if requesting manager has access permissions to it.",
  "method": "GET",
  "url": "/api/v1/products/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "pTBv3zw8Vpqj-Rcu1Ltl3",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "pTBv3zw8Vpqj-Rcu1Ltl3"
  },
  "results": {
    "languages": [
      {
        "id": "anQV3vsFBZ0ycbpvTZlo2",
        "language": "200",
        "code": "{\n    \"id\": 1584723961091234,\n    \"upgrade_from\": [],\n    \"product_features\": [\n        {\n            \"id\": 171,\n            \"created_at\": \"2020-08-26T05:36:46Z\",\n            \"updated_at\": \"2020-08-26T05:36:46Z\",\n            \"name\": \"Feature 1\",\n            \"code\": \"f1\",\n            \"is_deleted\": false,\n            \"feature_type\": \"activation\",\n            \"max_consumption\": 0,\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"reset_consumption\": false,\n            \"consumption_period\": null,\n            \"metadata\": {},\n        },\n        {\n            \"id\": 172,\n            \"created_at\": \"2020-08-26T05:37:14Z\",\n            \"updated_at\": \"2020-08-26T05:37:14Z\",\n            \"name\": \"Feature 2\",\n            \"code\": \"f2\",\n            \"is_deleted\": false,\n            \"feature_type\": \"consumption\",\n            \"max_consumption\": 20,\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"reset_consumption\": false,\n            \"consumption_period\": null,\n            \"metadata\": {},\n        }\n    ],\n    \"custom_fields\": [\n        {\n            \"id\": 51,\n            \"name\": \"Some key\",\n            \"data_type\": null,\n            \"default_value\": \"1234\",\n            \"description\": null\n        },\n        {\n            \"id\": 60,\n            \"name\": \"test_name\",\n            \"data_type\": null,\n            \"default_value\": \"123\",\n            \"description\": null\n        },\n        {\n            \"id\": 61,\n            \"name\": \"Key with space\",\n            \"data_type\": null,\n            \"default_value\": \"123\",\n            \"description\": null\n        }\n    ],\n    \"installation_files\": [\n        {\n            \"id\": 733282,\n            \"created_at\": \"2020-10-13T09:15:22Z\",\n            \"updated_at\": \"2020-10-13T09:15:22Z\",\n            \"version\": \"0.1\",\n            \"full_link\": \"https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf\",\n            \"filename\": \"dummy.pdf\",\n            \"release_date\": \"2020-10-09\",\n            \"enabled\": true,\n            \"hash_md5\": \"\",\n            \"environment\": \"linux\"\n        },\n        {\n            \"id\": 733283,\n            \"created_at\": \"2020-10-13T09:15:52Z\",\n            \"updated_at\": \"2020-10-13T09:15:52Z\",\n            \"version\": \"0.2\",\n            \"full_link\": \"https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf\",\n            \"filename\": \"dummy.pdf\",\n            \"release_date\": \"2020-10-10\",\n            \"enabled\": true,\n            \"hash_md5\": \"sonotahash\",\n            \"environment\": \"linux\"\n        }\n    ],\n    \"created_at\": \"2020-07-03T13:05:25Z\",\n    \"updated_at\": \"2020-07-07T12:35:05Z\",\n    \"product_name\": \"mch\",\n    \"short_code\": \"mch\",\n    \"active\": true,\n    \"valid_duration\": \"\",\n    \"allow_trial\": false,\n    \"trial_days\": 0,\n    \"max_activations\": 1,\n    \"hardware_id_required\": false,\n    \"is_upgrade\": false,\n    \"subscription_duration\": \"\",\n    \"enable_maintenance_period\": false,\n    \"maintenance_duration\": \"\",\n    \"is_floating\": true,\n    \"is_floating_cloud\": false,\n    \"floating_users\": 12,\n    \"floating_timeout\": 120,\n    \"default_license_type\": \"perpetual\",\n    \"is_user_locked\": false,\n    \"is_node_locked\": true,\n    \"max_consumptions\": 1,\n    \"authorization_method\": \"user\",\n    \"prevent_vm\": false,\n    \"allow_overages\": false,\n    \"max_overages\": 0,\n    \"reset_consumption\": false,\n    \"consumption_period\": null,\n    \"is_archived\": false,\n    \"metadata\": {},\n    \"company\": 277\n}",
        "customLabel": ""
      },
      {
        "id": "_5FA_MZ2UyJ2P7UTXGBTz",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "anQV3vsFBZ0ycbpvTZlo2"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "retrieve-a-single-product-if-requesting-manager-ha",
  "legacyHash": "O9yRzIusdtioDbchlhfJM"
}
```
:::


[title] Metadata Filtering
[path] Management API/

To filter by object's metadata which is stored as JSON a query parameter with `metadata` prefix must be sent in the URL. Here are some examples of how this filtering works:

## Filter by whole metadata value

Query param: `metadata={"key1":"value1"}`

Response:

```json
[
    ...
    "metadata": {
        "key1": "value1"
    }
]
```

## Filter by string key value

Query param: `metadata__key1="value1"`

Response:

```json
[
    {
        ...
        "metadata": {
            "key1": "value1"
        }
    },
    {
        ...
        "metadata": {
            "key1": "value1",
            "key2": "value2"
        }
    }
]
```

## Filter by number key value

Query param: `metadata__key1=123`

Response:

```json
[
    {
        ...
        "metadata": {
            "key1": 123
        }
    }
]
```

## Filter by array key value

Query param: `metadata__key1=[1, 2, 3]`

Response:

```json
[
    {
        ...
        "metadata": {
            "key1": [
                1,
                2,
                3
            ]
        }
    }
]
```

## Filter by object key value

Query param: `metadata__key1={"key2": "value2"}`

Response:

```json
[
    {
        ...
        "metadata": {
            "key1": {
                "key2": "value2"
            }
        }
    }
]
```

## Filter by boolen key value

Query param: `metadata__key1=true`

Response:

```json
[
    {
        ...
        "metadata": {
            "key1": true
        }
    }
]
```

## Filter by null key value

Query param: `metadata__key1=null`

Response:

```json
[
    {
        ...
        "metadata": {
            "key1": null
        }
    }
]
```

## Filter by nested key value

Query param: `metadata__key1__key2__key3="value3"`

Response:

```json
[
    {
        ...
        "metadata": {
            "key1": {
                "key2": {
                    "key3": "value3"
                }
            }
        }
    }
]
```

## Filter by array item

Query param: `metadata__key1__0=1`

Response:

```json
[
    {
        ...
        "metadata": {
            "key1": [
                1,
                2,
                3
            ]
        }
    }
]
```

## Filter by array containing item

Query param: `metadata__key1__contains=1`

Response:

```json
[
    {
        "metadata": {
            "key1": [
                1,
                2,
                3
            ]
        }
    },
    {
        "metadata": {
            "key1": [
                3,
                2,
                1
            ]
        }
    }
]
```


[title] List Customers
[path] Management API/Customer/

:::ApiMethodV2
```json
{
  "name": "Show all customers the requesting manager has access permissions to.",
  "method": "GET",
  "url": " /api/v1/customers/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "x_iMBDHSsFCZdzYzR969f",
        "language": "json",
        "code": "{\n    \"count\": 9,\n    \"next\": null,\n    \"previous\": null,\n    \"results\": [\n        {\n            \"id\": 620,\n            \"total_orders\": 52,\n            \"total_licenses\": 117,\n            \"labels\": [\n                {\n                    \"id\": 3,\n                    \"label_id\": 8,\n                    \"label\": \"Customer\",\n                    \"color\": \"#ff9f43\"\n                },\n                {\n                    \"id\": 53,\n                    \"label_id\": 34,\n                    \"label\": \"Loyal\",\n                    \"color\": \"#3a0cd4\"\n                }\n            ],\n            \"customer_account\": null,\n            \"email\": \"tc@tc.com\",\n            \"first_name\": \"Nameo\",\n            \"last_name\": \"\",\n            \"company_name\": \"\",\n            \"phone\": \"\",\n            \"reference\": \"\",\n            \"address\": \"\",\n            \"postcode\": \"\",\n            \"city\": \"\",\n            \"country\": \"\",\n            \"state\": \"\",\n            \"clabels_all\": \"customerloyal\",\n            \"cognito_user_pool_id\": \"\",\n            \"metadata\": {},\n            \"company\": 277,\n            \"license_user\": 1879,\n            \"clabels\": [\n                8,\n                34\n            ]\n        },\n        ...\n    ]\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "x_iMBDHSsFCZdzYzR969f"
  },
  "results": {
    "languages": [
      {
        "id": "aMXHPVtcZRkNOiLQYP-KZ",
        "language": "200",
        "code": "Code: 200 OK",
        "customLabel": ""
      },
      {
        "id": "EAPHeg84r4hGuNXoPgQ4P",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "aMXHPVtcZRkNOiLQYP-KZ"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "show-all-customers-the-requesting-manager-has-acce",
  "legacyHash": "31kacB6agcHSlHW37GvUq"
}
```
:::

### Query Parameters:

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on customer or related to the customer.

Possible filters:

- `label__in`
- `email`
- `email__icontains`
- `email__startswith`
- `company_name__icontains`
- `first_name__icontains`
- `last_name__icontains`
- `phone__icontains`
- `reference`
- `reference__icontains`
- `reference__startswith`
- `account`
- `account__name`
- `account__name__icontains`
- `account__code`
- `account__code__icontains`
- `account__description`
- `account__description__icontains`
- `account__phone`
- `account__phone__icontains`
- `account__address`
- `account__address__icontains`
- `account__email`
- `account__email__icontains`
- `account__reference`
- `account__reference__icontains`
- `metadata`


[title] Release Floating License
[path] License API/Floating/License/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/floating/release",
  "name": "/api/v4/floating/release",
  "method": "POST",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "String",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "kind": "optional",
        "name": "license_key",
        "type": "string",
        "children": [],
        "description": "Required if product is key-based (see section below)"
      },
      {
        "kind": "optional",
        "name": "username",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "Number",
        "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "children": []
      }
    ],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "es8g1cuKJMbNPiIVt9VoF",
        "code": "",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "7eyIlKSv2QgJcowEsDZ-2",
        "code": "{\n    \"unknown_product\": \"Provided product was not found\",\n    \"license_not_found\": \"License with the provided license user not found\",\n    \"license_not_enabled\": \"The license is not enabled\",\n    \"blacklisted\": \"This device is blacklisted\",\n    \"device_not_found\": \"An active device matching the hardware_id not found.\",\n\n    \n",
        "language": "400",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "es8g1cuKJMbNPiIVt9VoF"
  },
  "examples": {
    "languages": [
      {
        "id": "wY6kNLeBmDxj9aaSh7li1",
        "language": "curl",
        "code": "curl --location --request POST '/api/v4/floating/release' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string' \\\n--data-raw '{\"hardware_id\":\"String\",\"product\":\"string\",\"license_key\":\"string\",\"username\":\"string\"}'",
        "customLabel": ""
      },
      {
        "id": "yYis-CQhZFRCtOkluqspj",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'POST',\n   'url': '/api/v4/floating/release',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   },\n   body: '{\"hardware_id\":\"String\",\"product\":\"string\",\"license_key\":\"string\",\"username\":\"string\"}'\n\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "xbGX01BVvOPV-CHDPqJp4",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar raw = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\"}\";\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/floating/release\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "dFp4F3zS5sV2OsAFZ23UJ",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/floating/release\"\n\npayload = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\"}\"\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "T8H2NhR4EBc-WscAwr9d-",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/floating/release\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\nrequest.body = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\"}\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "T8H2NhR4EBc-WscAwr9d-"
  },
  "description": "Releases a floating cloud license from the current device and removes the device from the floating pool",
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4floatingrelease",
  "legacyHash": "FAy1CuDdz-zAzosWJNYqM"
}
```
:::

## Schema

### Request Body

:::CodeblockTabs
```typescript
type ReleaseFloatingLicenseRequestBody = {
  
  // required parameters:
  product: string,
  hardware_id: string,
  
  // required for key-based products:
  license_key: string
  
  // required for user-based products:
  username: string
  
  // optional parameters:
  license_id?: string | undefined,
}
```

JSON Schema

```json
```
:::

### Response Body

:::CodeblockTabs
```typescript
type ReleaseFloatingLicenseResponseBody = ''
```

JSON Schema

```json
```
:::

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

- **Key-based product licenses**: client interactions with the license have to be authorized using a `license_key`
- **User-based product licenses**: the license has a corresponding "license user" instead of a license key. Client interactions with the license have to be authorized using a `username`&#x20;

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**license\_not\_found&#x20;**(400): License with the provided license user not found
:::

:::BlockQuote
**license\_not\_active** (400): The license is not active
:::

:::BlockQuote
**license\_not\_enabled** (400): The license is not enabled
:::

:::BlockQuote
**device\_not\_found** (400): An active device matching the hardware\_id not found
:::

:::BlockQuote
**blacklisted** (400): This device is blacklisted
:::

:::BlockQuote
**floating\_not\_available** (400): No available slots for floating license
:::


[title] OAuth
[path] Management API/

You can manage [**OAuth Configuration**](docId\:q1YECed3KGhZMwcSX2MOJ)  credentials for LicenseAPI communication directly within the Management API.

[title] Remove Label From Customer
[path] Management API/Customer/Labels/

:::ApiMethodV2
```json
{
  "name": "Removes a label from customer, if requesting manager has access permissions to it.",
  "method": "DELETE",
  "url": "/api/v1/customerclabels/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "MFZYliqtq6HhKO7kSACF_",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "MFZYliqtq6HhKO7kSACF_"
  },
  "results": {
    "languages": [
      {
        "id": "HXMf5AixVs09nAoyUIv2O",
        "language": "200",
        "code": "Code: 200 OK",
        "customLabel": ""
      },
      {
        "id": "8VltoeUxZcOSSwDoK-cP_",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "HXMf5AixVs09nAoyUIv2O"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "removes-a-label-from-customer-if-requesting-manage",
  "legacyHash": "1v2jai-dzHP42-R4vJR2l"
}
```
:::



[title] Export Products
[path] Management API/Product/

:::ApiMethodV2
```json
{
  "name": "Exports products to csv if requesting manager has access permissions to them.",
  "method": "GET",
  "url": "api/v1/products/export/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "lRUzaQVbj7qQy1qhQqKxp",
        "language": "null",
        "code": "\"id\",\"created_at\",\"updated_at\",\"product_name\",\"short_code\",\"active\",\"valid_duration\",\"trial_days\",\"max_activations\",\"hardware_id_required\",\"is_upgrade\",\"allow_trial\",\"enable_maintenance_period\",\"floating_users\",\"is_floating\",\"is_node_locked\",\"is_user_locked\",\"maintenance_duration\",\"subscription_duration\",\"default_license_type\",\"max_consumptions\",\"authorization_method\",\"prevent_vm\",\"consumption_period\",\"max_overages\",\"reset_consumption\",\"is_archived\",\"is_floating_cloud\",\"floating_timeout\",\"is_bundle\",\"metadata\"\n90001,\"2023-03-16 11:35:24+00:00\",\"2023-03-16 11:35:24+00:00\",\"LKP1\",\"LKP1\",True,\"\",0,1,False,False,False,False,0,False,True,False,\"\",\"\",\"perpetual\",1,\"license-key\",False,\"\",0,False,False,False,120,False,\"{}\"\n90002,\"2023-03-16 11:35:24+00:00\",\"2023-03-16 11:35:24+00:00\",\"LKP2\",\"LKP2\",True,\"\",0,1,False,False,False,False,0,False,True,False,\"\",\"\",\"perpetual\",1,\"license-key\",False,\"\",0,False,False,False,120,False,\"{}\"\n90003,\"2023-03-16 11:35:24+00:00\",\"2023-03-16 11:35:24+00:00\",\"LKP3\",\"lkp3\",True,\"\",0,1,False,False,False,False,0,False,True,False,\"\",\"\",\"perpetual\",1,\"license-key\",False,\"\",0,False,False,False,120,False,\"{}\"\n90004,\"2023-03-16 11:55:02+00:00\",\"2023-03-16 11:55:02+00:00\",\"LKPB\",\"lkpb\",True,\"1y\",15,1,True,False,True,False,1,False,True,False,\"1y\",\"1m\",\"perpetual\",1,\"license-key\",False,\"\",0,False,False,False,120,False,\"{}\"\n90005,\"2023-03-16 11:55:02+00:00\",\"2023-03-16 11:55:02+00:00\",\"lkpwf\",\"lkpwf\",True,\"1y\",15,1,True,False,True,False,1,False,True,False,\"1y\",\"1m\",\"perpetual\",1,\"license-key\",False,\"\",0,False,False,False,120,False,\"{}\"\n90006,\"2023-03-16 11:55:02+00:00\",\"2023-03-16 11:55:02+00:00\",\"up\",\"up\",True,\"1y\",15,1,True,False,True,False,1,False,True,False,\"1y\",\"1m\",\"perpetual\",1,\"user\",False,\"\",0,False,False,False,120,False,\"{}\"\n90007,\"2023-03-16 11:55:02+00:00\",\"2023-03-16 11:55:02+00:00\",\"lkpwcf\",\"lkpwcf\",False,\"1y\",15,1,True,False,True,False,1,False,True,False,\"1y\",\"1m\",\"perpetual\",1,\"license-key\",False,\"\",0,False,False,False,120,False,\"{}\"\n90008,\"2023-03-16 11:55:02+00:00\",\"2023-03-16 11:55:02+00:00\",\"lkpwcf1\",\"lkpwcf1\",True,\"1y\",15,1,True,False,True,False,1,False,True,False,\"1y\",\"1m\",\"perpetual\",1,\"license-key\",False,\"\",0,False,False,False,120,True,\"{}\"\n90009,\"2023-03-16 11:55:02+00:00\",\"2023-03-16 11:55:02+00:00\",\"lkpwcf11\",\"lkpwcf11\",True,\"1y\",15,1,True,False,True,False,1,False,True,False,\"1y\",\"1m\",\"perpetual\",1,\"license-key\",False,\"\",0,False,False,False,120,False,\"{}\"\n1741773419655484,\"2025-03-12 09:56:59.658244+00:00\",\"2025-03-12 09:56:59.658259+00:00\",\"Product A\",\"PA\",True,\"1y\",15,1,True,False,True,False,1,False,True,False,\"1y\",\"1m\",\"perpetual\",1,\"license-key\",False,\"\",0,False,False,False,120,False,\"{}\"\n1741773419667541,\"2025-03-12 09:56:59.668945+00:00\",\"2025-03-12 09:56:59.668957+00:00\",\"Product B\",\"PB\",True,\"1y\",15,1,True,False,True,False,1,False,True,False,\"1y\",\"1m\",\"perpetual\",1,\"license-key\",False,\"\",0,False,False,False,120,False,\"{}\"",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "lRUzaQVbj7qQy1qhQqKxp"
  },
  "results": {
    "languages": [
      {
        "id": "RmC2g5Afglo3OKng4d7vr",
        "language": "200",
        "code": "200 OK",
        "customLabel": ""
      },
      {
        "id": "ywJ8lI9oK_wTiKQNmVItJ",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "RmC2g5Afglo3OKng4d7vr"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "exports-products-to-csv-if-requesting-manager-has",
  "legacyHash": "sORag8uoJuDl-y0QYfRfU"
}
```
:::


[title] Create Customer
[path] Management API/Customer/

:::ApiMethodV2
```json
{
  "name": "Creates a customer, if requesting manager has access permissions to it.",
  "method": "POST",
  "url": "/api/v1/customers/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "KzyHtS8RLa32B3IdxDrtW",
        "language": "json",
        "code": "{\n    \"email\": \"tc3@tc.com\",\n    \"first_name\": \"Harry\",\n    \"last_name\": \"Potter\",\n    \"company_name\": \"Hogwarts\",\n    \"phone\": \"+385913111111\",\n    \"reference\": \"ref123\",\n    \"address\": \"Street 1\",\n    \"postcode\": \"10000\",\n    \"city\": \"New York\",\n    \"country\": \"US\",\n    \"state\": \"NY\",\n    \"customer_account\": 1,\n    \"metadata\": {}\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "KzyHtS8RLa32B3IdxDrtW"
  },
  "results": {
    "languages": [
      {
        "id": "jc1ErDVyPWy1ee1nLTUJi",
        "language": "200",
        "code": "{\n    \"id\": 4165,\n    \"total_orders\": 0,\n    \"total_licenses\": 0,\n    \"labels\": [],\n    \"customer_account\": null,\n    \"email\": \"tc3@tc.com\",\n    \"first_name\": \"Harry\",\n    \"last_name\": \"Potter\",\n    \"company_name\": \"Hogwarts\",\n    \"phone\": \"+385913111111\",\n    \"reference\": \"ref123\",\n    \"address\": \"Street 1\",\n    \"postcode\": \"10000\",\n    \"city\": \"New York\",\n    \"country\": \"US\",\n    \"state\": \"NY\",\n    \"clabels_all\": null,\n    \"company\": 277,\n    \"license_user\": null,\n    \"clabels\": [],\n    \"cognito_user_pool_id\": \"\",\n    \"",
        "customLabel": ""
      },
      {
        "id": "piKNqoZIOKQySBlLPxlqp",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "jc1ErDVyPWy1ee1nLTUJi"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "email",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "email"
      },
      {
        "name": "first_name",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "first_name"
      },
      {
        "name": "last_name",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "last_name"
      },
      {
        "name": "company_name",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "company_name"
      },
      {
        "name": "phone",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "phone"
      },
      {
        "name": "reference",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "reference"
      },
      {
        "name": "address",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "address"
      },
      {
        "name": "postcode",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "postcode"
      },
      {
        "name": "city",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "city"
      },
      {
        "name": "country",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "country"
      },
      {
        "name": "state",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "state"
      },
      {
        "name": "customer_account",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "metadata",
        "kind": "optional",
        "type": "object",
        "description": "JSON Object",
        "": "JSON Object"
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "creates-a-customer-if-requesting-manager-has-acces",
  "legacyHash": "yjyVvCixvW5b7LcD997FT"
}
```
:::


[title] Retrieve Product Feature
[path] Management API/Product/Features/

:::ApiMethodV2
```json
{
  "name": "Retrieve a single product feature, if requesting manager has access permissions to it.",
  "method": "GET",
  "url": "/api/v1/product-features/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "ipdk9pyq7TO-o1VhBV9dg",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "ipdk9pyq7TO-o1VhBV9dg"
  },
  "results": {
    "languages": [
      {
        "id": "CXgOsqKXHUOEAbohuxPg5",
        "language": "200",
        "code": "{\n    \"id\": 560,\n    \"created_at\": \"2023-10-30T10:18:51Z\",\n    \"updated_at\": \"2023-10-30T10:22:09Z\",\n    \"name\": \"f1\",\n    \"code\": \"f1\",\n    \"is_deleted\": false,\n    \"feature_type\": \"consumption\",\n    \"max_consumption\": 7,\n    \"allow_unlimited_consumptions\": false,\n    \"allow_overages\": false,\n    \"max_overages\": 0,\n    \"reset_consumption\": false,\n    \"consumption_period\": null,\n    \"is_floating\": true,\n    \"is_floating_cloud\": false,\n    \"floating_users\": 13,\n    \"floating_timeout\": 113,\n    \"metadata\": {},\n    \"product\": 1698659666691556\n}",
        "customLabel": ""
      },
      {
        "id": "CjHEF3vs79r3jca1z1xsi",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "CXgOsqKXHUOEAbohuxPg5"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "retrieve-a-single-product-feature-if-requesting-ma",
  "legacyHash": "O-i3jnegNGWbpgl-DxOBg"
}
```
:::


[title] Delete Product custom field enumeration
[path] Management API/Product/Custom Field Enumerations/

:::ApiMethodV2
```json
{
  "name": "Delete a single product custom field enumeration if requesting manager has access permissions to it.",
  "method": "DELETE",
  "url": "/api/v1/product-custom-field-enums/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "m9FiCSc4NXeFm6wp8g3YI",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "m9FiCSc4NXeFm6wp8g3YI"
  },
  "results": {
    "languages": [
      {
        "id": "VN_MToUaCUmFsphv2U3e6",
        "language": "200",
        "code": "Code : 200 OK",
        "customLabel": ""
      },
      {
        "id": "-K_xOVdXyl7V0S-0jm0jY",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "VN_MToUaCUmFsphv2U3e6"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "delete-a-single-product-custom-field-enumeration-i",
  "legacyHash": "06KkvNvKETF7VKmzmvA6l"
}
```
:::

``

[title] Features
[path] License API/Floating/

## Floating Features

Floating features in a product are special capabilities that can be accessed by a limited number of users at the same time. These features come with settings for **Max Simultaneous Feature Users** and **Floating Timeout** which dictate the number of users who can simultaneously use the feature.  API allows  are "**Check-In**" and "**Release**" of Floating feature

Here you can find more details about [**Floating Features**](https://docs.licensespring.com/sdks/tutorials/licensing-scenarios/floating-features) in our tutorial

[title] Remove manager from Customer Account
[path] Management API/Customer/Accounts/

:::ApiMethodV2
```json
{
  "name": "Removes a manager from a single Customer Account.",
  "method": "POST",
  "url": " /api/v1/customer-accounts/{id}/remove_manager/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "kTfU8vaGdR4Hy2yo4QI4P",
        "language": "json",
        "code": "{\n    \"license_user_id\": 3420\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "kTfU8vaGdR4Hy2yo4QI4P"
  },
  "results": {
    "languages": [
      {
        "id": "-7zqKN4Va-AxKQ3PzvVSh",
        "language": "200",
        "code": "{\n    \"id\": 3420,\n    \"true_email\": \"example@gmail.com\",\n    \"is_initial_password\": true,\n    \"initial_password\": \"test1234\",\n    \"first_name\": \"First 1\",\n    \"last_name\": \"Last 1\",\n    \"phone_number\": \"\",\n    \"new_user\": false\n}",
        "customLabel": ""
      },
      {
        "id": "bJNEwNY2BNROQs_DnXBm9",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "-7zqKN4Va-AxKQ3PzvVSh"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "removes-a-manager-from-a-single-customer-account",
  "legacyHash": "Ih1krG0KTBl_LMjEMWeUM"
}
```
:::





[title] List Product custom field enumerations
[path] Management API/Product/Custom Field Enumerations/

:::ApiMethodV2
```json
{
  "name": "Show all product custom field enumerations the requesting manager has access permissions to.",
  "method": "GET",
  "url": "/api/v1/product-custom-field-enums/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "ld1M9Tw20QxmKuRzfwJes",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "ld1M9Tw20QxmKuRzfwJes"
  },
  "results": {
    "languages": [
      {
        "id": "Bi47OhzlxFH2ktHTyk_9p",
        "language": "200",
        "code": "{\n    \"count\": 2,\n    \"next\": null,\n    \"previous\": null,\n    \"results\": [\n        {\n            \"id\": 1,\n            \"value\": \"vv1\",\n            \"product_custom_field\": 69\n        },\n        ...\n    ]\n}",
        "customLabel": ""
      },
      {
        "id": "pSw39C9Qgy3LkVnXEZVr_",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "Bi47OhzlxFH2ktHTyk_9p"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "show-all-product-custom-field-enumerations-the-req",
  "legacyHash": "-8kHnkPEzC_pmIQ3hE5bG"
}
```
:::

### Query parameters

### Pagination

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering

The results can be filtered by various attributes on product custom field enumeration or related to the product custom field enumeration.

Possible filters:

- `product_custom_field`


[title] Borrow Floating Feature
[path] License API/Floating/Features/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/floating/feature_borrow",
  "name": "/api/v4/floating/feature_borrow",
  "method": "POST",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "String",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "String",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "name": "borrowed_until",
        "kind": "required",
        "type": "string",
        "description": "Timestamp until license is borrowed. ISO 8601 format (always in UTC timezone)",
        "children": []
      },
      {
        "name": "feature",
        "kind": "required",
        "type": "string",
        "description": "Feature code",
        "": "Feature code"
      },
      {
        "kind": "optional",
        "name": "license_key",
        "type": "string",
        "children": [],
        "description": "Required if product is key-based (see section below)"
      },
      {
        "kind": "optional",
        "name": "username",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "name": "password",
        "kind": "optional",
        "type": "string",
        "description": "Required if product is user based (see section below)",
        "children": []
      },
      {
        "name": "id_token",
        "kind": "optional",
        "type": "string",
        "description": "Required if using SSO with Implicit grant authorization. This is the id_token received from the SSO.",
        "": "Required if using SSO with Implicit grant authorization. This is the id_token received from the SSO."
      },
      {
        "name": "code",
        "kind": "optional",
        "type": "string",
        "description": "Required if using SSO with Authorization code grant. This is the code received from the SSO.",
        "": "Required if using SSO with Authorization code grant. This is the code received from the SSO."
      },
      {
        "name": "customer_account_code",
        "kind": "optional",
        "type": "string",
        "description": "Required if using SSO. This is the customer_account_code to which SSO provider is configured.",
        "": "Required if using SSO. This is the customer_account_code to which SSO provider is configured."
      },
      {
        "name": "redirect_uri",
        "kind": "optional",
        "type": "string",
        "description": "Required if using SSO with multiple redirect URIs enabled. This value is the redirect URI you used to obtain the SSO token or code",
        "": "Required if using SSO with multiple redirect URIs enabled. This value is the redirect URI you used to obtain the SSO token or code"
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "Number",
        "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "children": []
      }
    ],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "es8g1cuKJMbNPiIVt9VoF",
        "language": "200",
        "code": "{\n    \"borrowed_until\": \"2022-05-06T00:00:00Z\",\n    \"max_borrow_time\": 48,\n    \"device_id\": 1648212707135009,\n    \"license_id\": 1622536481402629,\n    \"floating_in_use_devices\": 0,\n    \"company\": { \"id\": 123 }\n}",
        "customLabel": ""
      },
      {
        "id": "7eyIlKSv2QgJcowEsDZ-2",
        "language": "400",
        "code": "{\n    \"unknown_product\": \"Provided product was not found\",\n    \"license_not_found\": \"License with the provided license user not found\",\n    \"license_not_enabled\": \"The license is not enabled\",\n    \"blacklisted\": \"This device is blacklisted\",\n    \"device_not_found\": \"An active device matching the hardware_id not found.\",\n\n    \ndodaj jos",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "es8g1cuKJMbNPiIVt9VoF"
  },
  "examples": {
    "languages": [
      {
        "id": "V0XPpDWJ6Z-prQFzb1iCk",
        "language": "curl",
        "code": "curl --location --request POST '/api/v4/floating/feature_borrow' \\\n--header 'Accept: application/json' \\\n--header 'Date: string' \\\n--header 'Authorization: string' \\\n--data-raw '{\"hardware_id\":\"String\",\"product\":\"string\",\"feature\":\"string\",\"license_key\":\"string\",\"username\":\"string\"}'",
        "customLabel": ""
      },
      {
        "id": "QSGFqLS9Yj7eeCnvEaKJe",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'POST',\n   'url': '/api/v4/floating/borrow',\n   'headers': {\n      'Accept': 'application/json',\n      'Date': 'string',\n      'Authorization': 'string'\n   },\n   body: '{\"hardware_id\":\"String\",\"product\":\"string\",\"license_key\":\"string\",\"username\":\"string\"}'\n\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "HL5nweu5_Mt8Sh2FqtX-2",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Date\", \"string\");\nmyHeaders.append(\"Authorization\", \"string\");\n\nvar raw = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\"}\";\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/floating/borrow\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "0QrYgeoue7U2OB9d3-uhC",
        "language": "python",
        "code": "import requests\n\nurl = \"/api/v4/floating/borrow\"\n\npayload = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\"}\"\nheaders = {\n   'Accept': 'application/json',\n   'Date': 'string',\n   'Authorization': 'string'\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "A7K8gbzDnazn4Oq1-rZrI",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/floating/borrow\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Date\"] = \"string\"\nrequest[\"Authorization\"] = \"string\"\nrequest.body = \"{\\\"hardware_id\\\":\\\"String\\\",\\\"product\\\":\\\"string\\\",\\\"license_key\\\":\\\"string\\\",\\\"username\\\":\\\"string\\\"}\"\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "V0XPpDWJ6Z-prQFzb1iCk"
  },
  "description": "Borrows a floating cloud license\n",
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "apiv4floatingfeatureborrow",
  "legacyHash": "bf3LMlNO9PSQ6WjdwzSpZ"
}
```
:::

:::hint{type="info"}
Send null as a value for borrowed\_until if you wan't to set borrowed\_until to max\_borrow\_time from now + max\_borrow\_time value defined on a license.
:::

## Schema

### Request Body

:::CodeblockTabs
```typescript
type BorrowFloatingFeatureRequestBody = {
  
  // required parameters:
  product: string,
  hardware_id: string,
  feature: string,
  
  /**
   * `borrowed_until` is a string in ISO 8601 format (always in UTC timezone).
   * It contains a date component and optional time component, e.g.:
   * "2024-09-27T23:30:48.016Z"
   * "2024-09-27 23:30:48.016"
   * "2024-09-27 23:30:48"
   * "2024-09-27 23:30"
   * "2024-09-27"
   */
  borrowed_until: string,
  
  // required for key-based products:
  license_key?: string,
  
  // required for user-based products:
  username?: string,
  password?: string,
  
  // required for SSO with Implicit grant authorization:
  id_token?: string,
  
  // required for SSO with Authorization code grant:
  code?: string,
  
  // required for SSO with either authorization method:
  customer_acount_id?: string,
  
  // optional parameters:
  license_id?: string | undefined,
}
```

JSON Schema

```json
```
:::

### Response Body

:::CodeblockTabs
```typescript
type BorrowFloatingLicenseResponseBody = {
    borrowed_until: string, // date in ISO8061 format
    max_borrow_time: number, // hours
    device_id: number,
    license_id: number,
    floating_in_use_devices: number,
    company: { id: number },
}
```

JSON Schema

```json
```
:::

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

- **Key-based product licenses**: client interactions with the license have to be authorized using a `license_key`
- **User-based product licenses**: the license has a corresponding "license user" instead of a license key. Client interactions with the license have to be authorized using a `username` and `password`

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**missing\_headers** (400): Some headers are missing
:::

:::BlockQuote
**missing\_parameters&#x20;**(400): Some parameters are missing in the request: \{ params }.
:::

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**license\_not\_found&#x20;**(400): License with the provided license user not found
:::

:::BlockQuote
**license\_not\_active** (400): The license is not active
:::

:::BlockQuote
**invalid\_license\_feature\_code** (400): License feature code \{code} is invalid or not assigned to the license.
:::

:::BlockQuote
**feature\_not\_floating** (400): License feature is not floating cloud feature.
:::

:::BlockQuote
**borrow\_until\_not\_valid** (400): Borrow until field is not valid
:::

:::BlockQuote
**device\_not\_found** (400): An active device matching the hardware\_id not found
:::

:::BlockQuote
**blacklisted** (400): This device is blacklisted
:::

:::BlockQuote
**floating\_not\_available** (400): No available slots for floating license
:::


[title] List Customer Accounts
[path] Management API/Customer/Accounts/

:::ApiMethodV2
```json
{
  "name": "Show all customer accounts the requesting manager has access permissions to.",
  "method": "GET",
  "url": "/api/v1/customer-accounts/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "BC4AyNnqxv7gCFubd8Hwt",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "BC4AyNnqxv7gCFubd8Hwt"
  },
  "results": {
    "languages": [
      {
        "id": "23j86a9viICroBOfXSY-U",
        "language": "200",
        "code": "{\n    \"count\": 2,\n    \"next\": null,\n    \"previous\": null,\n    \"results\": [\n        {\n            \"id\": 811,\n            \"customers_count\": 0,\n            \"code\": \"tc4\",\n            \"name\": \"Test Customer Company 4\",\n            \"description\": \"\",\n            \"phone\": \"\",\n            \"address\": \"\",\n            \"email\": \"\",\n            \"cognito_user_pool_id\": \"\",\n            \"company\": 339\n        },\n        ...\n    ]\n}",
        "customLabel": ""
      },
      {
        "id": "h_a1gYwdMjUXEoMNjFAvC",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "23j86a9viICroBOfXSY-U"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "show-all-customer-accounts-the-requesting-manager",
  "legacyHash": "uVT9s8g4C9CshJaEr3Vuw"
}
```
:::

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on customer account or related to the customer account.

Possible filters:

- `code`
- `name`
- `description`
- `phone`
- `address`
- `email`
- `reference`
- `metadata`

###


[title] Delete Customer Label
[path] Management API/Customer/Labels/

:::ApiMethodV2
```json
{
  "name": "Delete a single Customer label, if requesting manager has access permissions to it.",
  "method": "DELETE",
  "url": " /api/v1/clabels/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "epKsEsJ2ua2CWGYyTeqHS",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "epKsEsJ2ua2CWGYyTeqHS"
  },
  "results": {
    "languages": [
      {
        "id": "DVQu9Gyb3NgeT-JNKGxJ5",
        "language": "200",
        "code": "Code: 200 OK",
        "customLabel": ""
      },
      {
        "id": "pXaTaLJQ697KTlt_Cubdj",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "DVQu9Gyb3NgeT-JNKGxJ5"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "delete-a-single-customer-label-if-requesting-manag",
  "legacyHash": "--2K1DCuNyh6ew2bFSu2-"
}
```
:::


[title] Management API Authorization
[path] Management API/

All requests to the server need to be authorized with the management API key. A management API key is sent as an authorization header value.

Each request from the client needs to have the following header:

- `Authorization`, with the following value: `Api-Key _here_is_the_management_api_key_`

### Example:

Management API key for this example is `h8ZTleS1.OyCHhCST5c8K9A6gjV9wA1HLxWpUVSFv`.

Header:

- `Authorization: Api-Key h8ZTleS1.OyCHhCST5c8K9A6gjV9wA1HLxWpUVSFv`

Full sample code for getting a license key with management API key:

```python
import requests

API_URL = 'https://saas.licensespring.com'

# Can be found in `Settings` -> `Settings` -> `Keys`
API_KEY = '_your_management_api_key_goes_here_'

# Send request
product_short_code = '_your_product_short_code_goes_here_'
quantity = 1 # Replace with desired quantity

response = requests.get(
    url='{}{}'.format(API_URL, '/api/v1/orders/generate_license/'),
    params={'product': product_short_code, 'quantity': quantity},
    headers={
        'Authorization': 'Api-Key {}'.format(API_KEY)
    }
)

print(response.json())
```


[title] Products
[path] License API/


[title] Licenses for User
[path] License API/List Licenses/

:::ApiMethodV2
```json
{
  "name": "List user licenses",
  "method": "GET",
  "url": "/api/v4/user_licenses",
  "description": "Returns a list of licenses assigned to a user for a product (only for user-based product licenses)",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "nJooa8Sw1kofn5iPWkm0F",
        "language": "javascript",
        "code": "const headers = new Headers();\nheaders.append(\"Accept\", \"application/json\");\nheaders.append(\"Date\", \"DATE_STRING\");\nheaders.append(\"Authorization\", \"AUTHORIZATION_STRING\");\n\nconst requestOptions = {\n  method: 'GET',\n  headers: headers,\n  redirect: 'follow'\n};\n\nconst queryParams = new URLSearchParams({\n  product: 'PRODUCT_STRING',\n  username: 'USERNAME_STRING',\n  password: 'PASSWORD_STRING',\n})\n.toString();\n\nfetch(\"/api/v4/user_licenses?\" + queryParams, requestOptions)\n  .then(response => response.text())\n  .then(result => console.log(result))\n  .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "wsr6xyQvbNW2pHl9kw0C7",
        "language": "curl",
        "code": "curl --location --request GET '/api/v4/user_licenses?product=PRODUCT_STRING&username=USERNAME_STRING&password=PASSWORD_STRING' \\\n--header 'Accept: application/json' \\\n--header 'Date: DATE_STRING' \\\n--header 'Authorization: AUTHORIZATION_STRING'\n\n# NOTE: since this is a GET request, make sure the query parameters are url-encoded",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "wsr6xyQvbNW2pHl9kw0C7"
  },
  "results": {
    "languages": [
      {
        "id": "1JLWp1hW3a0_JxHZ6U2-d",
        "language": "200",
        "customLabel": "",
        "code": "[\n    {\n        \"license\": {\n            \"id\": 10003,\n            \"order_store_id\": \"store_id_for_order_3\",\n            \"license_active\": true,\n            \"license_enabled\": true,\n            \"license_type\": \"perpetual\",\n            \"is_trial\": false,\n            \"max_license_users\": 1,\n            \"validity_period\": null,\n            \"enable_maintenance_period\": false,\n            \"maintenance_period\": null,\n            \"allow_grace_period\": false,\n            \"grace_period\": 0,\n            \"max_activations\": 1,\n            \"allow_unlimited_activations\": false,\n            \"times_activated\": 1,\n            \"start_date\": null,\n            \"transfer_count\": 0,\n            \"max_transfers\": 0,\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"is_floating_cloud\": false,\n            \"is_floating\": false,\n            \"floating_timeout\": 120,\n            \"can_borrow\": false,\n            \"max_borrow_time\": 0,\n            \"prevent_vm\": false,\n            \"custom_fields\": [],\n            \"product_features\": [],\n            \"customer\": {\n                \"email\": \"somecustomer@somedomain.com\",\n                \"company_name\": \"Some Company\",\n                \"reference\": \"ref_for_customer_1\",\n                \"phone\": \"\",\n                \"first_name\": \"\",\n                \"last_name\": \"\",\n                \"city\": \"\",\n                \"postcode\": \"\",\n                \"state\": \"\",\n                \"country\": \"\",\n                \"address\": \"\",\n                \"customer_account\": null,\n                \"metadata\": {}\n            },\n            \"product_details\": {\n                \"product_id\": 10006,\n                \"product_name\": \"User Product\",\n                \"short_code\": \"up\",\n                \"authorization_method\": \"user\",\n                \"metadata\": {}\n            },\n            \"metadata\": {},\n            \"is_hardware_key_auth\": false,\n            \"is_air_gapped\": false\n        },\n        \"user\": {\n            \"id\": 10003,\n            \"email\": \"someuser@somedomain.com\",\n            \"first_name\": \"Some\",\n            \"last_name\": \"User\",\n            \"phone_number\": \"\",\n            \"is_initial_password\": true,\n            \"max_activations\": 1,\n            \"allow_unlimited_activations\": false,\n            \"total_activations\": 1\n        }\n    },\n    {\n        \"license\": {\n            \"id\": 1719215304208059,\n            \"order_store_id\": \"trial_1719215304208039\",\n            \"license_active\": true,\n            \"license_enabled\": true,\n            \"license_type\": \"perpetual\",\n            \"is_trial\": true,\n            \"max_license_users\": 1,\n            \"validity_period\": \"2031-03-16\",\n            \"enable_maintenance_period\": false,\n            \"maintenance_period\": null,\n            \"allow_grace_period\": false,\n            \"grace_period\": 0,\n            \"max_activations\": 1,\n            \"allow_unlimited_activations\": false,\n            \"times_activated\": 1,\n            \"start_date\": null,\n            \"transfer_count\": 3,\n            \"max_transfers\": 2,\n            \"allow_overages\": false,\n            \"max_overages\": 0,\n            \"is_floating_cloud\": false,\n            \"is_floating\": false,\n            \"floating_timeout\": 120,\n            \"can_borrow\": false,\n            \"max_borrow_time\": 0,\n            \"prevent_vm\": false,\n            \"custom_fields\": [],\n            \"product_features\": [],\n            \"customer\": {\n                \"email\": \"someuser@somedomain.com\",\n                \"company_name\": \"\",\n                \"reference\": \"\",\n                \"phone\": \"\",\n                \"first_name\": \"\",\n                \"last_name\": \"\",\n                \"city\": \"\",\n                \"postcode\": \"\",\n                \"state\": \"\",\n                \"country\": \"\",\n                \"address\": \"\",\n                \"customer_account\": null,\n                \"metadata\": {}\n            },\n            \"product_details\": {\n                \"product_id\": 10006,\n                \"product_name\": \"User Product\",\n                \"short_code\": \"up\",\n                \"authorization_method\": \"user\",\n                \"metadata\": {}\n            },\n            \"metadata\": {},\n            \"is_hardware_key_auth\": false,\n            \"is_air_gapped\": false,\n            \"trial_days\": 15\n        },\n        \"user\": {\n            \"id\": 10003,\n            \"email\": \"someuser@somedomain.com\",\n            \"first_name\": \"Some\",\n            \"last_name\": \"User\",\n            \"phone_number\": \"\",\n            \"is_initial_password\": true,\n            \"max_activations\": 1,\n            \"allow_unlimited_activations\": false,\n            \"total_activations\": 1\n        }\n    }\n]"
      },
      {
        "id": "0UjeUVgaV19IFSSAKOzvK",
        "language": "404",
        "customLabel": "",
        "code": ""
      }
    ],
    "selectedLanguageId": "0UjeUVgaV19IFSSAKOzvK"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [
      {
        "name": "product",
        "kind": "optional",
        "type": "string",
        "description": "Short code of product, filters results by specified product",
        "children": []
      },
      {
        "name": "username",
        "kind": "optional",
        "type": "string",
        "description": "User's username (if using user authentication, not SSO authentication)",
        "children": []
      },
      {
        "name": "password",
        "kind": "optional",
        "type": "string",
        "description": "User's password (if using user authentication, not SSO authentication)",
        "children": []
      },
      {
        "name": "customer_account_code",
        "kind": "optional",
        "type": "string",
        "description": "Required if using SSO (see section below). This is the customer_account_code to which SSO provider is configured",
        "children": []
      },
      {
        "name": "id_token",
        "kind": "optional",
        "type": "string",
        "description": "Required if using SSO. This is the id_token received from the SSO if Implicit grant authorization method is being used.",
        "": "Required if using SSO. This is the id_token received from the SSO if Implicit grant authorization method is being used."
      },
      {
        "name": "code",
        "kind": "optional",
        "type": "string",
        "description": "Required if using SSO. This is the code received from the SSO if Authorization code grant method is being used.",
        "": "Required if using SSO. This is the code received from the SSO if Authorization code grant method is being used."
      },
      {
        "name": "redirect_uri",
        "kind": "optional",
        "type": "string",
        "description": "Required if using SSO with multiple redirect URIs enabled. This value is the redirect URI you used to obtain the SSO token or code",
        "": "Required if using SSO with multiple redirect URIs enabled. This value is the redirect URI you used to obtain the SSO token or code"
      }
    ],
    "headerParameters": [
      {
        "name": "Date",
        "kind": "required",
        "type": "string",
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT",
        "children": []
      },
      {
        "name": "Authorization",
        "kind": "required",
        "type": "string",
        "description": "See \"License API Authorization\" article",
        "children": []
      }
    ],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Query Parameter",
    "value": "queryParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "list-user-licenses",
  "legacyHash": "nl6z4wiomXynAO7Vx-TtV"
}
```
:::

## Schema

### Request Query Parameters

:::CodeblockTabs
```typescript
type LicensesForUserRequestParameters = {
  
  product: string,
  
} & ({

  // for username and password authentication:
  username: string
  password: string

} | {

  // for single sign-on Implicit grant authentication:
  id_token: string
  customer_account_code: string

} | {

  // for single sign-on using Authorization code grant authentication:
  code: string
  customer_account_code: string

})
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "oneOf": [
    {
      "type": "object",
      "properties": {
        "license_key": { "type": "string" }
      },
      "required": ["license_key"],
      "additionalProperties": false
    },
    {
      "type": "object",
      "properties": {
        "username": { "type": "string" },
        "password": { "type": "string" }
      },
      "required": ["username", "password"],
      "additionalProperties": false
    },
    {
      "type": "object",
      "properties": {
        "id_token": { "type": "string" },
        "customer_account_code": { "type": "string" }
      },
      "required": ["id_token", "customer_account_code"],
      "additionalProperties": false
    },
    {
      "type": "object",
      "properties": {
        "code": { "type": "string" },
        "customer_account_code": { "type": "string" }
      },
      "required": ["code", "customer_account_code"],
      "additionalProperties": false
    }
  ]
}
```
:::

### Response Body

:::CodeblockTabs
```typescript
type LicenseListResponseBody = ({
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  borrowed_until: string | null, // in ISO 8601 format (always in UTC timezone), e.g. 2024-09-27T23:30:48.016Z or 2024-09-27 23:30
  can_borrow: boolean,
  channel: string,
  device_id: number,
  enable_maintenance_period: boolean
  environment: string,
  eula_link: string,
  floating_timeout: number,
  grace_period: number,
  hash_md5: string,
  installation_file: string,
  is_air_gapped: boolean,
  is_borrowed: boolean,
  is_expired: boolean,
  is_floating_cloud: boolean,
  is_floating: boolean,
  is_hardware_key_auth: boolean,
  license_active: boolean,
  license_enabled: boolean,
  license_signature: string,
  license_signature_v2: string,
  offline_signature: string,
  license_type: string,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users: number,
  max_overages: number,
  max_transfers: number,
  order_store_id: string,
  prevent_vm: boolean,
  release_date: string,
  release_notes_link: string,
  requires_version: string,
  size: string,
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null, // string is in DateISO8601UTC format
  version: string,
  company: { id: number },
  
  product_features: ({
    id: number,
    code: string,
    name: string,
    expiry_date: string,
    metadata: JSON,
    feature_type: 'activation' | 'consumption',
    is_floating: boolean,
    is_floating_cloud: boolean,

    // the following properties are only present if is_floating=true or is_floating_cloud=true
    floating_users: number,
    floating_timeout: number,

    // the following properties are only present if feature_type=consumption
    max_consumption: number,
    allow_unlimited_consumptions: boolean,
    total_consumptions: number,
    allow_overages: number,
    max_overages: number,
    reset_consumption: boolean,
    consumption_period: 'daily' | 'weekly' | 'monthly' | 'annualy' | null,
  })[],
  
  custom_fields: ({
    name: string,
    data_type: 'numer' | 'text' | 'date/time',
    value: string,
  })[],
  
  customer: {
    email: string,
    company_name: string,
    reference: string,
    phone: string,
    first_name: string,
    last_name: string,
    city: string,
    postcode: string,
    state: string,
    country: string,
    address: string,
    customer_account: string | null,
    metadata: JSON,
  },
  
  product_details: {
    product_id: number,
    product_name: string,
    short_code: string,
    authorization_method: 'license-key' | 'user',
    metadata: JSON,
  },
  
  // NOTE: all licenses in this response are for user-based products
  
  user: {
    id: number,
    email: string,
    first_name: string,
    last_name: string,
    phone_number: string,
    is_initial_password: boolean,
    max_activations: number,
    allow_unlimited_activations: boolean,
    total_activations: number
  },
  
  metadata: JSON,
  
  // the following property is only present if is_trial=true
  trial_days: number,
  
  // the following properties is only present if is_floating=true or is_floating_cloud=true
  floating_in_use_devices: number,
  floating_users: number,
  
  // the following properties are only present if license_type='consumption'
  max_consumptions: number,
  total_consumptions: number,
  allow_unlimited_consumptions: boolean,
  reset_consumption: boolean,
  consumption_period: string | null, // string is in DateISO8601UTC format
  
})[];
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "id": { "type": "number" },
      "allow_grace_period": { "type": "boolean" },
      "allow_overages": { "type": "boolean" },
      "allow_unlimited_activations": { "type": "boolean" },
      "borrowed_until": { "type": ["string", "null"] },
      "can_borrow": { "type": "boolean" },
      "channel": { "type": "string" },
      "device_id": { "type": "number" },
      "enable_maintenance_period": { "type": "boolean" },
      "environment": { "type": "string" },
      "eula_link": { "type": "string" },
      "floating_timeout": { "type": "number" },
      "grace_period": { "type": "number" },
      "hash_md5": { "type": "string" },
      "installation_file": { "type": "string" },
      "is_air_gapped": { "type": "boolean" },
      "is_borrowed": { "type": "boolean" },
      "is_expired": { "type": "boolean" },
      "is_floating_cloud": { "type": "boolean" },
      "is_floating": { "type": "boolean" },
      "is_hardware_key_auth": { "type": "boolean" },
      "license_active": { "type": "boolean" },
      "license_enabled": { "type": "boolean" },
      "license_signature": { "type": "string" },
      "license_signature_v2": { "type": "string" },
      "offline_signature": { "type": "string" },
      "license_type": { "type": "string" },
      "maintenance_period": { "type": ["string", "null"] },
      "max_activations": { "type": "number" },
      "max_borrow_time": { "type": "number" },
      "max_license_users": { "type": "number" },
      "max_overages": { "type": "number" },
      "max_transfers": { "type": "number" },
      "order_store_id": { "type": "string" },
      "prevent_vm": { "type": "boolean" },
      "release_date": { "type": "string" },
      "release_notes_link": { "type": "string" },
      "requires_version": { "type": "string" },
      "size": { "type": "string" },
      "start_date": { "type": ["string", "null"] },
      "times_activated": { "type": "number" },
      "transfer_count": { "type": "number" },
      "validity_period": { "type": ["string", "null"] },
      "version": { "type": "string" },
      "company": { "type": "object", "properties": {"id": { "type": "number" } } },
      "product_features": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "id": { "type": "number" },
            "code": { "type": "string" },
            "name": { "type": "string" },
            "expiry_date": { "type": "string" },
            "metadata": { "type": "object" },
            "feature_type": { "type": "string", "enum": ["activation", "consumption"] },
            "is_floating": { "type": "boolean" },
            "is_floating_cloud": { "type": "boolean" },
            "floating_users": { "type": "number" },
            "floating_timeout": { "type": "number" },
            "max_consumption": { "type": "number" },
            "allow_unlimited_consumptions": { "type": "boolean" },
            "total_consumptions": { "type": "number" },
            "allow_overages": { "type": "number" },
            "max_overages": { "type": "number" },
            "reset_consumption": { "type": "boolean" },
            "consumption_period": {
              "type": ["string", "null"],
              "enum": ["daily", "weekly", "monthly", "annualy", null]
            }
          },
          "required": ["id", "code", "name", "expiry_date", "metadata", "feature_type", "is_floating", "is_floating_cloud"]
        }
      },
      "custom_fields": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "name": { "type": "string" },
            "data_type": { "type": "string", "enum": ["numer", "text", "date/time"] },
            "value": { "type": "string" }
          },
          "required": ["name", "data_type", "value"]
        }
      },
      "customer": {
        "type": "object",
        "properties": {
          "email": { "type": "string" },
          "company_name": { "type": "string" },
          "reference": { "type": "string" },
          "phone": { "type": "string" },
          "first_name": { "type": "string" },
          "last_name": { "type": "string" },
          "city": { "type": "string" },
          "postcode": { "type": "string" },
          "state": { "type": "string" },
          "country": { "type": "string" },
          "address": { "type": "string" },
          "customer_account": { "type": ["string", "null"] },
          "metadata": { "type": "object" }
        },
        "required": ["email", "company_name", "reference", "phone", "first_name", "last_name", "city", "postcode", "state", "country", "address", "metadata"]
      },
      "product_details": {
        "type": "object",
        "properties": {
          "product_id": { "type": "number" },
          "product_name": { "type": "string" },
          "short_code": { "type": "string" },
          "authorization_method": { "type": "string", "enum": ["license-key", "user"] },
          "metadata": { "type": "object" }
        },
        "required": ["product_id", "product_name", "short_code", "authorization_method", "metadata"]
      },
      "user": {
        "type": "object",
        "properties": {
          "id": { "type": "number" },
          "email": { "type": "string" },
          "first_name": { "type": "string" },
          "last_name": { "type": "string" },
          "phone_number": { "type": "string" },
          "is_initial_password": { "type": "boolean" },
          "max_activations": { "type": "number" },
          "allow_unlimited_activations": { "type": "boolean" },
          "total_activations": { "type": "number" }
        },
        "required": ["id", "email", "first_name", "last_name", "phone_number", "is_initial_password", "max_activations", "allow_unlimited_activations", "total_activations"]
      },
      "metadata": { "type": "object" },
      "trial_days": { "type": "number" },
      "floating_users": { "type": "number" },
      "max_consumptions": { "type": "number" },
      "total_consumptions": { "type": "number" },
      "allow_unlimited_consumptions": { "type": "boolean" },
      "reset_consumption": { "type": "boolean" },
      "consumption_period": { "type": ["string", "null"] }
    },
    "required": [
      "id",
      "allow_grace_period",
      "allow_overages",
      "allow_unlimited_activations",
      "can_borrow",
      "channel",
      "device_id",
      "enable_maintenance_period",
      "environment",
      "eula_link",
      "floating_timeout",
      "grace_period",
      "hash_md5",
      "installation_file",
      "is_air_gapped",
      "is_borrowed",
      "is_expired",
      "is_floating_cloud",
      "is_floating",
      "is_hardware_key_auth",
      "license_active",
      "license_enabled",
      "license_signature",
      "license_signature_v2",
      "offline_signature",
      "license_type",
      "max_activations",
      "max_borrow_time",
      "max_license_users",
      "max_overages",
      "max_transfers",
      "order_store_id",
      "prevent_vm",
      "release_date",
      "release_notes_link",
      "requires_version",
      "size",
      "times_activated",
      "transfer_count",
      "user",
      "version",
      "product_features",
      "custom_fields",
      "product_details",
      "metadata"
    ],
    "additionalProperties": false
  }
}

```
:::

## License Authorization Method

The licenses returned by this endpoint are allways user-based product licenses. This means they don't have a license key, and instead each license has a "license user".

Accessing this endpoint requires license user authentication, which can be done in three ways:

- By providing the values for `username` and `password` for the license user
- By providing the values for `id_token` and `customer_account_code` if using single sign-on authentication using Implicit grant
- By providing the values for `code` and `customer_account_code` if using single sign-on authentication using Authorization code grant

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions


[title] 
[path] Management API/Product/


[title] Management API
[path] /

The Management APIs are intended for organizations to edit existing license entitlements and orders. It is intended as a back office API where every action that can be achieved inside the vendor platform can be done also programmatically using this API.

:::hint{type="danger"}
These APIs have destructive capability and should not be client facing, or distributed with a client application.
:::

Base URL: **saas.licensespring.com**

You can retrieve your Management API key from within your account by going to Account Settings > Settings > Keys


[title] Add manager to Customer Account
[path] Management API/Customer/Accounts/

:::ApiMethodV2
```json
{
  "name": "Adds a manager to a single Customer Account.",
  "method": "POST",
  "url": "/api/v1/customer-accounts/{id}/add_manager/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "sNw7uoEE5MlLEssK-TQOq",
        "language": "json",
        "code": "{\n    \"email\": \"example@gmail.com\",\n    \"password\": \"Test1234!43210\",\n    \"first_name\": \"First 1\",\n    \"last_name\": \"Last 1\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "sNw7uoEE5MlLEssK-TQOq"
  },
  "results": {
    "languages": [
      {
        "id": "OEWvm9fPOP_ze0gLCKB9C",
        "language": "200",
        "code": "{\n    \"id\": 3621,\n    \"true_email\": \"example@gmail.com\",\n    \"is_initial_password\": true,\n    \"initial_password\": \"Test1234!43210\",\n    \"first_name\": \"First 1\",\n    \"last_name\": \"Last 1\",\n    \"phone_number\": \"\",\n    \"new_user\": true,\n    \"password\": \"Test1234!43210\"\n}",
        "customLabel": ""
      },
      {
        "id": "nWH-3qEF1POb_Vz4xOod-",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "OEWvm9fPOP_ze0gLCKB9C"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "adds-a-manager-to-a-single-customer-account",
  "legacyHash": "R7-SJeO1MoNipEtrzHQH0"
}
```
:::


[title] Release Floating Feature
[path] License API/Floating/Features/

:::ApiMethodV2
```json
{
  "tab": "examples",
  "url": "/api/v4/floating/feature_release",
  "name": "/api/v4/floating/feature_release",
  "method": "POST",
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [
      {
        "kind": "required",
        "name": "Date",
        "type": "string",
        "children": [],
        "description": "In RFC7231 format (see \"License API Authorization\"), eg.: Thu, 17 Nov 2022 20:51:35 GMT"
      },
      {
        "kind": "required",
        "name": "Authorization",
        "type": "string",
        "children": [],
        "description": "See \"License API Authorization\" article"
      }
    ],
    "bodyDataParameters": [
      {
        "kind": "required",
        "name": "hardware_id",
        "type": "String",
        "children": [],
        "description": "Unique hardware ID generated for the client device"
      },
      {
        "kind": "required",
        "name": "product",
        "type": "string",
        "children": [],
        "description": "Product short code"
      },
      {
        "name": "feature",
        "kind": "required",
        "type": "string",
        "description": "feature code",
        "children": []
      },
      {
        "kind": "optional",
        "name": "license_key",
        "type": "string",
        "children": [],
        "description": "Required if product is key-based (see section below)"
      },
      {
        "kind": "optional",
        "name": "username",
        "type": "string",
        "children": [],
        "description": "Required if product is user based (see section below)"
      },
      {
        "name": "license_id",
        "kind": "optional",
        "type": "Number",
        "description": "Ensures that the action affects only the license with the specified ID. This is useful if e.g. you have multiple licenses for the same product assigned to the same user. For obtaining a list of licenses assigned to a user, see \"User Licenses\"",
        "children": []
      }
    ],
    "formDataParameters": []
  },
  "results": {
    "languages": [
      {
        "id": "es8g1cuKJMbNPiIVt9VoF",
        "code": "",
        "language": "200",
        "customLabel": ""
      },
      {
        "id": "7eyIlKSv2QgJcowEsDZ-2",
        "code": "{\n    \"unknown_product\": \"Provided product was not found\",\n    \"license_not_found\": \"License with the provided license user not found\",\n    \"license_not_enabled\": \"The license is not enabled\",\n    \"blacklisted\": \"This device is blacklisted\",\n    \"device_not_found\": \"An active device matching the hardware_id not found.\",\n\n    \n",
        "language": "400",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "es8g1cuKJMbNPiIVt9VoF"
  },
  "examples": {
    "languages": [
      {
        "id": "GKoknmHSN2LLAgZTjolOH",
        "language": "curl",
        "code": "curl --location --request POST '/api/v4/floating/feature_release' \\\n--header 'Accept: application/json' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\"hardware_id\":\"String\",\"product\":\"string\",\"feature\":\"string\",\"license_key\":\"string\",\"username\":\"string\"}'",
        "customLabel": ""
      },
      {
        "id": "bbNY8xi6G1LPXeDQMV-3g",
        "language": "nodejs",
        "code": "var request = require('request');\nvar options = {\n   'method': 'POST',\n   'url': '/api/v4/floating/feature_release',\n   'headers': {\n      'Accept': 'application/json',\n      'Content-Type': 'application/json'\n   },\n   body: JSON.stringify({\n      \"hardware_id\": \"String\",\n      \"product\": \"string\",\n      \"feature\": \"string\",\n      \"license_key\": \"string\",\n      \"username\": \"string\"\n   })\n\n};\nrequest(options, function (error, response) {\n   if (error) throw new Error(error);\n   console.log(response.body);\n});\n",
        "customLabel": ""
      },
      {
        "id": "4dD-4o-k5IuXwm6GaCj6i",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Content-Type\", \"application/json\");\n\nvar raw = JSON.stringify({\n   \"hardware_id\": \"String\",\n   \"product\": \"string\",\n   \"feature\": \"string\",\n   \"license_key\": \"string\",\n   \"username\": \"string\"\n});\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"/api/v4/floating/feature_release\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "nK2b0Fgo8L4QKgSvWWReo",
        "language": "python",
        "code": "import requests\nimport json\n\nurl = \"/api/v4/floating/feature_release\"\n\npayload = json.dumps({\n   \"hardware_id\": \"String\",\n   \"product\": \"string\",\n   \"feature\": \"string\",\n   \"license_key\": \"string\",\n   \"username\": \"string\"\n})\nheaders = {\n   'Accept': 'application/json',\n   'Content-Type': 'application/json'\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n",
        "customLabel": ""
      },
      {
        "id": "E2vpKyUjWQ488cRzLsIP-",
        "language": "ruby",
        "code": "require \"uri\"\nrequire \"json\"\nrequire \"net/http\"\n\nurl = URI(\"/api/v4/floating/feature_release\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.dump({\n   \"hardware_id\": \"String\",\n   \"product\": \"string\",\n   \"feature\": \"string\",\n   \"license_key\": \"string\",\n   \"username\": \"string\"\n})\n\nresponse = http.request(request)\nputs response.read_body\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "GKoknmHSN2LLAgZTjolOH"
  },
  "description": "Releases a floating license feature which is currently being borrowed by a license device",
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "apiv4floatingfeaturerelease",
  "legacyHash": "FAy1CuDdz-zAzosWJNYqM"
}
```
:::

## Schema

### Request Body

:::CodeblockTabs
```typescript
type ReleaseFlotingFeatureRequestBody = {
  
  // required parameters:
  product: string,
  hardware_id: string,
  feature: string,
  
  // required for key-based products:
  license_key: string,
  
  // required for user-based products:
  username: string,
  
  // optional parameters:
  license_id?: string | undefined,
}
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "allOf": [
    {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "license_key": { "type": "string" }
          },
          "required": ["license_key"],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "username": { "type": "string" }
          },
          "required": ["username"],
          "additionalProperties": false
        }
      ]
    },
    {
      "type": "object",
      "properties": {
        "hardware_id": { "type": "string" },
        "product": { "type": "string" },
        "feature": { "type": "string" },
        "license_id": { "type": ["number", "null"] }
      },
      "required": ["hardware_id", "product", "feature"],
      "additionalProperties": false
    }
  ]
}
```
:::

### Response Body

:::CodeblockTabs
```typescript
type ReleaseFlotingFeatureResponseBody = ''
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "string",
}
```
:::

## License Authorization Method

There are two types of product licenses based on how the client application authorizes itself to interact with a license:

- **Key-based product licenses**: client interactions with the license have to be authorized using a `license_key`
- **User-based product licenses**: the license has a corresponding "license user" instead of a license key. Client interactions with the license have to be authorized using a `username`&#x20;

## Errors

If an error occurs, the response will have an HTTP status code of 400 or higher, and the response body will contain an error description in the following format:

:::CodeblockTabs
```typescript
{
  status: number,
  code: string,
  message: string
}
```

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "status": { "type": "number" },
    "code": { "type": "string" },
    "message": { "type": "string" }
  },
  "required": [
    "status",
    "code",
    "message"
  ],
  "additionalProperties": false
}
```
:::

### List of exceptions

:::BlockQuote
**unknown\_product** (400): Provided product was not found
:::

:::BlockQuote
**license\_not\_found&#x20;**(400): License with the provided license user not found
:::

:::BlockQuote
**license\_not\_active** (400): The license is not active
:::

:::BlockQuote
**license\_not\_enabled** (400): The license is not enabled
:::

:::BlockQuote
**device\_not\_found** (400): An active device matching the hardware\_id not found
:::

:::BlockQuote
**blacklisted** (400): This device is blacklisted
:::

:::BlockQuote
**floating\_feature\_device\_not\_in\_use** (400): Floating feature device is not in use
:::

:::BlockQuote
**invalid\_license\_feature\_code** (400): License feature code: ' + param + ' is invalid or not assigned    to the license.
:::

:::BlockQuote
**feature\_not\_floating** (400): License feature is not floating cloud feature.
:::


[title] Delete Customer Account
[path] Management API/Customer/Accounts/

:::ApiMethodV2
```json
{
  "name": "Deletes a single customer account, if requesting manager has access permissions to it.",
  "method": "DELETE",
  "url": " /api/v1/customer-accounts/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "2bnEzI7K2LA31LoBQykCf",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "2bnEzI7K2LA31LoBQykCf"
  },
  "results": {
    "languages": [
      {
        "id": "_jimviCMwJ9Dae10sygXw",
        "language": "200",
        "code": "Code: 200 OK",
        "customLabel": ""
      },
      {
        "id": "6PqM4frFUX25_WMSa7BV-",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "_jimviCMwJ9Dae10sygXw"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "deletes-a-single-customer-account-if-requesting-ma",
  "legacyHash": "2iMhlpqeZ0mn3yHfItuOc"
}
```
:::




[title] List License Manager Permissions
[path] Management API/License/Managers/

List all supported license manager permissions.

**URL** : `/api/v1/license-manager-permissions/`

**Method** : `GET`

### Query parameters

### Pagination

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{
    "count": 14,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 10,
            "code": "borrow_license"
        },
        {
            "id": 11,
            "code": "create_bundle_order"
        },
        {
            "id": 8,
            "code": "create_license_policy"
        },
        {
            "id": 1,
            "code": "create_order"
        },
        {
            "id": 2,
            "code": "issue_license"
        },
        {
            "id": 13,
            "code": "manage_license_oauth_clients"
        },
        {
            "id": 4,
            "code": "manage_license_users"
        },
        {
            "id": 5,
            "code": "manage_license_user_credentials"
        },
        {
            "id": 3,
            "code": "manage_managers"
        },
        {
            "id": 7,
            "code": "reset_device"
        },
        {
            "id": 6,
            "code": "reset_license"
        },
        {
            "id": 12,
            "code": "revoke_device"
        },
        {
            "id": 14,
            "code": "show_license_oauth_clients"
        },
        {
            "id": 9,
            "code": "show_license_usage_report"
        }
    ]
}
```


[title] Unassign User from License
[path] Management API/License/

Unassigns a user from a single license, if requesting manager has access permissions to it.

**URL**: `/api/v1/licenses/{id}/unassign_user/`

**Method**: `POST`

### Data Example:

```json
{
    "license_user_id": 1585
}
```

or

```json
{
    "license_user_email": "user@example.com"
}
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "message": "License unassigned."
}
```


[title] List License Activation Histories
[path] Management API/License/Activation Histories/

Show all license activation histories the requesting manager has access permissions to.

**URL**: `/api/v1/license-activation-histories/`

**Method**: `GET`

### Query Parameters:

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on license activation history or related to the license activation history.

Possible filters:

- `license`
- `ts__gte`
- `ts__lte`
- `ts__date__gte`
- `ts__date__lte`
- `action`

### Success Response:

**Code**: `200 OK`

**Content examples**:

```json
{
    "count": 5,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 22,
            "device": {
                "id": 1112,
                "device_variables": [
                    {
                        "id": 2018,
                        "created_at": "2021-02-01T07:24:08Z",
                        "variable": "v7",
                        "value": "ggg",
                        "device": 1112
                    }
                ],
                "created_at": "2020-06-02T10:32:54Z",
                "updated_at": "2020-06-02T12:35:17Z",
                "hardware_id": "1C0B-D53D-2A92-9665-9634-1FE5-1326-56DF-5401-63B1-88D5-DB7D-FB02-D440-3760-720D",
                "time_activated": "2020-03-11T10:22:29Z",
                "time_deactivated": null,
                "validity_period": null,
                "device_active": true,
                "type": "desktop",
                "os": "Microsoft Home 10",
                "sdk_build_version": "Java SDK 0.0.1",
                "last_check": "2020-03-13T11:04:45Z",
                "app_ver": "1.0",
                "hostname": "DESKTOP-2K64QES",
                "ip": "192.168.202.1",
                "external_ip": "46.234.71.160",
                "mac_address": null,
                "is_vm": true,
                "vm_info": "VMware ESX 3",
                "floating_last_seen": null,
                "floating_in_use": false,
                "blacklisted": false,
                "license": 1599050404885519
            },
            "ts": "2021-03-17T11:15:51Z",
            "action": "activation",
            "license": 1599050404885519
        },
        ...
    ]
}
```


[title] Create License Product Feature
[path] Management API/License/ Features/

Creates a license product feature, if requesting manager has access permissions to it.

**URL**: `/api/v1/license-product-features/`

**Method**: `POST`

### Parameters:

- `license` - Integer
- `product_feature` - Integer
- `max_consumption` - Integer
- `allow_overages` - Boolean
- `consumption_period`
  - Choices: `daily`, `weekly`, `monthly`, `annualy `
- `reset_consumption` - Boolean
- `allow_unlimited_consumptions` - Boolean
- `metadata` - JSON
- `expiry_date` - Date
  - Fromat: `yyyy-mm-dd` (2020-09-30)
- `allow_unlimited_consumptions` - Bolean
- `floating_timeout` - Integer
- `is_floating` - Boolean
- `is_floating_cloud` - Boolean
- `floating_users` - Integer
- `allow_negative_consumptions` - Boolean

### Data Example:

```json
{
"license":1609234933166159,
"product_feature":128,
"max_consumption":80,
"expiry_date":"2029-12-12",
"allow_overages":false,
"consumption_period":"daily",
"max_overages":10,
"reset_consumption":1,
"allow_unlimited_consumptions":false,
"metadata":{},
"floating_timeout":160,
"is_floating":false,
"is_floating_cloud":true,
"allow_negative_consumptions":true
}
```

### Success Response:

**Code**: `201 OK`

**Content Examples**:

```json
{
    "id": 1728370200864113,
    "max_consumption": 80,
    "total_consumptions": 0,
    "allow_unlimited_consumptions": false,
    "allow_negative_consumptions": true,
    "expiry_date": "2029-12-12",
    "allow_overages": false,
    "max_overages": 10,
    "reset_consumption": true,
    "consumption_period": "daily",
    "is_floating": false,
    "is_floating_cloud": true,
    "floating_users": 1,
    "floating_timeout": 160,
    "metadata": {
        "b": "a"
    },
    "license": 1724914678024439,
    "product_feature": 170
}
```


[title] Assign User to License
[path] Management API/License/

Assigns a user to a single license, if requesting manager has access permissions to it.

**URL**: `/api/v1/licenses/{id}/assign_user/`

**Method**: `POST`

### Data Example:

```json
{
    "email": "example@email.com",
    "first_name": "John",
    "last_name": "Doe",
    "phone_number": "00385913109161",
    "is_manager": false,
    "password": "4q3dg7!_",
    "max_activations": 500,
    "total_activations": 200
}
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "message": "License assigned.",
    "new_password": "4q3dg7!_"
}
```


[title] Retrieve License Policy
[path] Management API/License/License Policies/

Retrieve a single license policy if requesting manager has access permissions to it.

**URL** : `/api/v1/license-templates/{id}/`

**Method** : `GET`

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{
    "id": 938,
    "license_product_feature_templates": [
        {
            "id": 246,
            "product_feature": {
                "id": 194,
                "created_at": "2021-01-13T08:38:38Z",
                "updated_at": "2021-01-13T08:38:38Z",
                "name": "f1",
                "code": "f1",
                "is_deleted": false,
                "feature_type": "activation",
                "max_consumption": 0,
                "allow_unlimited_consumptions": false,
                "allow_overages": false,
                "max_overages": 0,
                "reset_consumption": false,
                "consumption_period": null,
                "is_floating": false,
                "is_floating_cloud": false,
                "floating_users": 1,
                "floating_timeout": null,
                "metadata": {},
                "product": 1584723961091260
            },
            "feature_type": "activation",
            "max_consumption": 100,
            "allow_unlimited_consumptions": false,
            "allow_overages": false,
            "max_overages": 0,
            "reset_consumption": false,
            "consumption_period": null,
            "is_floating": false,
            "is_floating_cloud": false,
            "floating_users": 1,
            "floating_timeout": null,
            "metadata": {},
            "license_template": 938
        }
    ],
    "license_custom_field_templates": [
        {
            "id": 66,
            "product_custom_field": {
                "id": 69,
                "name": "cf44",
                "data_type": null,
                "default_value": "31",
                "description": null,
                "product": 1584723961091260
            },
            "name": "cf44",
            "data_type": null,
            "default_value": "69",
            "description": "Some description",
            "license_template": 938
        }
    ],
    "created_at": "2024-04-09T07:22:34.340092Z",
    "updated_at": "2024-04-09T07:22:34.340195Z",
    "name": "Example name",
    "code": "example_code",
    "is_default": false,
    "default_license_type": "perpetual",
    "allow_trial": true,
    "trial_days": 15,
    "max_activations": 100,
    "allow_unlimited_activations": false,
    "max_license_users": 1,
    "is_floating": true,
    "is_floating_cloud": true,
    "floating_users": 1,
    "floating_timeout": 120,
    "enable_maintenance_period": false,
    "maintenance_duration": "1y",
    "prevent_vm": false,
    "valid_duration": "1y",
    "allow_grace_period": false,
    "grace_period": 0,
    "max_consumptions": 1,
    "allow_unlimited_consumptions": false,
    "allow_overages": false,
    "max_overages": 0,
    "reset_consumption": false,
    "consumption_period": null,
    "max_transfers": 0,
    "is_air_gapped": false,
    "can_borrow": false,
    "max_borrow_time": 0,
    "is_archived": false,
    "is_hardware_key_auth": false,
    "validity_period": "2020-09-30",
    "metadata": {},
    "product": 1584723961091260,
    "installation_file": null,
    "is_sku": false,
    "user_max_activations": 3
}
```


[title] Update License Policy
[path] Management API/License/License Policies/

Updates a license policy if requesting manager has access permissions to it.

**URL** : `/api/v1/license-templates/{id}/`

**Method** : `PATCH`

### Parameters

- `name` - String
- `default_license_type` - String
- `allow_trial` - Boolean
- `trial_days` - Integer
- `max_activations` - Integer
- `allow_unlimited_activations` - Boolean
- `max_license_users` - Integer
- `is_floating` - Boolean
- `is_floating_cloud` - Boolean
- `floating_users` - Integer
- `floating_timeout` - Integer
- `enable_maintenance_period` - Boolean
- `maintenance_duration` - String
- `prevent_vm` - Boolean
- `valid_duration` - String
- `allow_grace_period` - Boolean
- `grace_period` - Integer
- `max_consumptions` - Integer
- `allow_unlimited_consumptions` - Boolean
- `allow_overages` - Boolean
- `max_overages` - Integer
- `reset_consumption` - Boolean
- `consumption_period` - Integer
- `max_transfers` - Integer
- `is_air_gapped` - Boolean
- `can_borrow` - Boolean
- `max_borrow_time` - Integer
- `is_archived` - Boolean
- `is_hardware_key_auth` - Boolean
- `installation_file` - Integer
- `is_sku` - Boolean
- `user_max_activations` - Integer
- `metadata` - JSON
- `license_product_feature_templates` - list of objects:
  - `id` - Integer (id of product feature)
  - `max_consumption` - Integer
  - `allow_unlimited_consumptions` - Boolean
  - `allow_overages` - Boolean
  - `max_overages` - Integer
  - `reset_consumption` - Boolean
  - `consumption_period` - String
  - `is_floating` - Boolean
  - `is_floating_cloud` - Boolean
  - `floating_users` - Integer
  - `floating_timeout` - Integer
  - `metadata` - JSON
- `license_custom_field_templates` - list of objects:
  - `id` - Integer (id of product custom field)
  - `name` - String
  - `data_type` - String
  - `default_value` - String
  - `description` - String

### Data example

```json
{
    "max_activations": 120
}
```

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{
    "id": 938,
    "license_product_feature_templates": [
        {
            "id": 246,
            "product_feature": {
                "id": 194,
                "created_at": "2021-01-13T08:38:38Z",
                "updated_at": "2021-01-13T08:38:38Z",
                "name": "f1",
                "code": "f1",
                "is_deleted": false,
                "feature_type": "activation",
                "max_consumption": 0,
                "allow_unlimited_consumptions": false,
                "allow_overages": false,
                "max_overages": 0,
                "reset_consumption": false,
                "consumption_period": null,
                "is_floating": false,
                "is_floating_cloud": false,
                "floating_users": 1,
                "floating_timeout": null,
                "metadata": {},
                "product": 1584723961091260
            },
            "feature_type": "activation",
            "max_consumption": 100,
            "allow_unlimited_consumptions": false,
            "allow_overages": false,
            "max_overages": 0,
            "reset_consumption": false,
            "consumption_period": null,
            "is_floating": false,
            "is_floating_cloud": false,
            "floating_users": 1,
            "floating_timeout": null,
            "metadata": {},
            "license_template": 938
        }
    ],
    "license_custom_field_templates": [
        {
            "id": 66,
            "product_custom_field": {
                "id": 69,
                "name": "cf44",
                "data_type": null,
                "default_value": "31",
                "description": null,
                "product": 1584723961091260
            },
            "name": "cf44",
            "data_type": null,
            "default_value": "69",
            "description": "Some description",
            "license_template": 938
        }
    ],
    "created_at": "2024-04-09T07:22:34.340092Z",
    "updated_at": "2024-04-09T08:32:11.553372Z",
    "name": "Example name",
    "code": "example_code",
    "is_default": false,
    "default_license_type": "perpetual",
    "allow_trial": true,
    "trial_days": 15,
    "max_activations": 120,
    "allow_unlimited_activations": false,
    "max_license_users": 1,
    "is_floating": true,
    "is_floating_cloud": true,
    "floating_users": 1,
    "floating_timeout": 120,
    "enable_maintenance_period": false,
    "maintenance_duration": "1y",
    "prevent_vm": false,
    "valid_duration": "1y",
    "allow_grace_period": false,
    "grace_period": 0,
    "max_consumptions": 1,
    "allow_unlimited_consumptions": false,
    "allow_overages": false,
    "max_overages": 0,
    "reset_consumption": false,
    "consumption_period": null,
    "max_transfers": 0,
    "is_air_gapped": false,
    "can_borrow": false,
    "max_borrow_time": 0,
    "is_archived": false,
    "is_hardware_key_auth": false,
    "metadata": {},
    "product": 1584723961091260,
    "installation_file": null,
    "is_sku": false
}
```


[title] Count License Transfers
[path] Management API/License/Activation Histories/

Counts license transfers, if requesting manager has access permissions to it.

License transfer counts as a license activation on a device different from the device it was last activated on.

**URL**: `/api/v1/license-activation-histories/transfer_count/`

**Method**: `GET`

### Filtering:

The results can be filtered by various attributes on license activation history or related to the license activation history.

Possible filters:

- `license`
- `ts__gte`
- `ts__lte`
- `ts__date__gte`
- `ts__date__lte`

### Success Response:

**Code**: `200 OK`

**Content Examples:**

```json
{
    "transfer_count": 5
}
```


[title] Add Manager to Order
[path] Management API/Order/

:::ApiMethodV2
```json
{
  "name": "Adds a order manager to a single order if requesting manager has access permissions to it.",
  "method": "POST",
  "url": "/api/v1/orders/{id}/add_manager/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "9L-OlqcOWYmOMqyoI9TIs",
        "language": "json",
        "code": "{\n    \"email\": \"example@email.com\",\n    \"password\": \"4q3dg7!_\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "9L-OlqcOWYmOMqyoI9TIs"
  },
  "results": {
    "languages": [
      {
        "id": "qEkL1vp3Z6sR8_TnP8csr",
        "language": "200",
        "code": "{\n    \"id\": 1941,\n    \"true_email\": \"example@email.com\",\n    \"is_initial_password\": true,\n    \"initial_password\": \"4q3dg7!_\",\n    \"first_name\": \"\",\n    \"last_name\": \"\",\n    \"phone_number\": \"\",\n    \"new_user\": true,\n    \"password\": \"4q3dg7!_\"\n}",
        "customLabel": ""
      },
      {
        "id": "I4KAHF6reJmgAt0wg_WSv",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "qEkL1vp3Z6sR8_TnP8csr"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "adds-a-order-manager-to-a-single-order-if-requesti",
  "legacyHash": "l0djxOjzO20alkWmOtZgR"
}
```
:::


[title] Retrieve License Activation History
[path] Management API/License/Activation Histories/

Retrieves a single license activation history, if requesting manager has access permissions to it.

**URL**: `/api/v1/license-activation-histories/{id}/`

**Method**: `GET`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 23,
    "device": {
        "id": 1112,
        "device_variables": [
            {
                "id": 2018,
                "created_at": "2021-02-01T07:24:08Z",
                "variable": "v7",
                "value": "ggg",
                "device": 1112
            }
        ],
        "created_at": "2020-06-02T10:32:54Z",
        "updated_at": "2020-06-02T12:35:17Z",
        "hardware_id": "1C0B-D53D-2A92-9665-9634-1FE5-1326-56DF-5401-63B1-88D5-DB7D-FB02-D440-3760-720D",
        "time_activated": "2020-03-11T10:22:29Z",
        "time_deactivated": null,
        "validity_period": null,
        "device_active": true,
        "type": "desktop",
        "os": "Microsoft Home 10",
        "sdk_build_version": "Java SDK 0.0.1",
        "last_check": "2020-03-13T11:04:45Z",
        "app_ver": "1.0",
        "hostname": "DESKTOP-2K64QES",
        "ip": "192.168.202.1",
        "external_ip": "46.234.71.160",
        "mac_address": null,
        "is_vm": true,
        "vm_info": "VMware ESX 3",
        "floating_last_seen": null,
        "floating_in_use": false,
        "blacklisted": false,
        "license": 1599050404885519
    },
    "ts": "2021-03-17T11:17:06Z",
    "action": "deactivation",
    "license": 1599050404885519
}
```


[title] Retrieve License Product Feature
[path] Management API/License/ Features/

Retrieve a single license feature, if requesting manager has access permissions to it.

**URL**: `/api/v1/license-product-features/{id}`

**Method**: `GET`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 1698661568105404,
    "product_feature": {
        "id": 560,
        "created_at": "2023-10-30T10:18:51Z",
        "updated_at": "2023-10-30T10:22:09Z",
        "name": "f1",
        "code": "f1",
        "is_deleted": false,
        "feature_type": "consumption",
        "max_consumption": 7,
        "allow_unlimited_consumptions": false,
        "allow_overages": false,
        "max_overages": 0,
        "reset_consumption": false,
        "consumption_period": null,
        "is_floating": true,
        "is_floating_cloud": false,
        "floating_users": 13,
        "floating_timeout": 113,
        "metadata": {}
    },
    "device_features": [],
    "max_consumption": 10,
    "total_consumptions": 0,
    "allow_unlimited_consumptions": false,
    "expiry_date": null,
    "allow_overages": false,
    "max_overages": 0,
    "reset_consumption": false,
    "consumption_period": "monthly",
    "is_floating": true,
    "is_floating_cloud": false,
    "floating_users": 10,
    "floating_timeout": 120,
    "metadata": {},
    "license": 1698659715613589
}
```


[title] Assign Users (Bulk) to License
[path] Management API/License/

Assigns multiple users to a single license, if requesting manager has access permissions to it.

**URL**: `/api/v1/licenses/{id}/assign_users/`

**Method**: `POST`

### Data Example:

```json
{
    "emails": [
        {
            "email": "test3@t.com",
            "is_manager": true
        },
        {
            "email": "test4@t.com",
            "is_manager": false
        }
    ]
}
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
[
    {
        "email": "test3@t.com",
        "new_user": false,
        "password": "N!8?d?ao"
    },
    {
        "email": "test4@t.com",
        "new_user": false,
        "password": "?Q4qAL1b"
    }
]
```


[title] List License Users
[path] Management API/License/Users/

Show all license users the requesting manager has access permissions to.

**URL**: `/api/v1/license-users/`

**Method**: `GET`

### Query Parameters:

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on license activation history or related to the license activation history.

Possible filters:

- `true_email__icontains`
- `true_email__iexact`
- `managing_orders__isnull`
- `first_name__icontains`
- `last_name__icontains`
- `phone__icontains`
- `is_license_manager`
- `managing_customer_accounts__isnull`
- `license__order__customer_account`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "count": 2,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 2270,
            "last_login": null,
            "email": "end-user@gmail.com|tn",
            "true_email": "end-user@gmail.com",
            "created_at": "2021-08-24T07:22:27Z",
            "updated_at": "2021-10-14T07:54:11Z",
            "is_active": true,
            "is_manager": false,
            "initial_password": "5dH7Oqfq",
            "is_initial_password": true,
            "first_name": "toni",
            "last_name": "sre",
            "phone_number": "123",
            "total_licenses": 1
        },
        ...
    ]
}
```


[title] Change Customer on Order
[path] Management API/Order/

:::ApiMethodV2
```json
{
  "name": "Change Customer on order",
  "method": "PATCH",
  "url": "/api/v1/orders/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "W9nb0b26e8RH-uu7ak0hS",
        "language": "json",
        "code": "{\n    \"customer\": 123\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "W9nb0b26e8RH-uu7ak0hS"
  },
  "results": {
    "languages": [
      {
        "id": "T7KHl8C6-EXj0AA1q3wTH",
        "language": "200",
        "code": "{\n    \"id\": 1629789747117569,\n    \"created_at\": \"2021-08-24T07:22:27Z\",\n    \"updated_at\": \"2021-11-23T07:04:07.441338Z\",\n    \"store_id\": \"patched_store_id\",\n    \"type\": \"normal\",\n    \"customer_email\": null,\n    \"is_test\": false,\n    \"customer_reference\": \"\",\n    \"is_trial\": false,\n    \"download_id\": null,\n    \"language\": null,\n    \"campaign_params\": null,\n    \"customer_first_name\": null,\n    \"customer_last_name\": null,\n    \"customer_company\": null,\n    \"customer_phone\": null,\n    \"metadata\": {},\n    \"company\": 339,\n    \"customer\": 123,\n    \"license_users\": []\n}",
        "customLabel": ""
      },
      {
        "id": "tNjLnt_jWOzoRy0UHSxsy",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "T7KHl8C6-EXj0AA1q3wTH"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "customer ",
        "kind": "required",
        "type": "integer",
        "description": "",
        "": "integer"
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "change-customer-on-order",
  "legacyHash": "Kx6TYUialQ2cHu5XYOri9"
}
```
:::


[title] 
[path] Management API/License/


[title] Create License User
[path] Management API/License/Users/

Creates a license user if requesting manager has access permissions to it.

**URL** : `/api/v1/license-users/`

**Method** : `POST`

### Parameters

- `email` - String
- `first_name` - String
- `last_name` - String
- `phone_number` - String
- `password` - String
- `metadata` - JSON

### Data example

```json
{
    "email": "tlucreation20@gmail.com",
    "metadata": {
        "this": "that"
    }
}
```

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{
    "id": 3490,
    "true_email": "tlucreation20@gmail.com",
    "is_initial_password": true,
    "initial_password": "bb!WBrmL",
    "first_name": "",
    "last_name": "",
    "phone_number": "",
    "new_user": true,
    "metadata": {
        "this": "that"
    },
    "password": "bb!WBrmL"
}
```


[title] Update License Manager Permissions
[path] Management API/License/Managers/

Updates permissions for a single license manager if requesting manager has access permissions to it.

**URL** : `/api/v1/license-users/{id}/update_lm_permissions/`

**Method** : `POST`

### Parameters

- `permission_ids` - List of License Manager Permission id integers
- `products` - List of objects:
  - `product_id` - Integer
  - `num_of_licenses` - Integer
- `license_template_ids` - List of License Template id integers
- `customer_account_ids` - List of Customer Account id integers

### Data example

```json
{
    "permission_ids": [
        1,
        2,
        4,
        5
    ],
    "products": [
        {
            "product_id": 1678966523782857,
            "num_of_licenses": 19
        },
        {
            "product_id": 1584723961091260,
            "num_of_licenses": null
        }
    ],
    "license_template_ids": [
        754,
        10,
        719
    ],
    "customer_account_ids": [
        834,
        837
    ]
}
```

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{}
```


[title] List Licenses Import Results
[path] Management API/License/Import Results/

Show all licenses import results the requesting manager has access permissions to.

**URL**: `/api/v1/licenses-import-results/`

**Method**: `GET`

### Query Parameters:

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on customer or related to the customer.

Possible filters:

- `status__iexact`
  - Choices: `pending`, `running`, `error`, `success`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "count": 9,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 14,
            "file_name": "simple_licenses_example.csv",
            "status": "success",
            "created_at": "2021-04-22T11:14:21.345069Z",
            "started_at": "2021-04-22T11:14:24.461055Z",
            "finished_at": "2021-04-22T11:14:26.861156Z",
            "result": {
                "total_row_count": 2,
                "valid_row_count": 2,
                "invalid_rows": [],
                "created_customers_count": 0,
                "existed_customers_count": 2,
                "created_orders_count": 1,
                "existed_orders_count": 1,
                "created_licenses_count": 2,
                "existed_licenses_count": 0
            }
        },
        ...
    ]
}
```


[title] Set Password for License User by Email
[path] Management API/License/Users/

Sets password for a single license user, if requesting manager has access permissions to it.

**URL**: `/api/v1/license-users/set_password/`

**Method**: `POST`

### Query Parameters:

- `email` - User's email address.
  - Example: `email=user@example.com`

### Data Example:

```json
{
    "password": "pass123"
}
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "message": "Password set."
}
```


[title] Create Installation File (cloned)
[path] Management API/Product/Installation Files/

Creates a installation file. if requesting manager has access permissions to it.

**URL**: `/api/v1/installation-files/`

**Method**: `POST`

### Parameters:

- `environment` - String
  - Choices: `win`, `win32`, `win64`, `mac`, `linux`, `linux32`, `linux64`
- `hash_md5` - String
- `full_link` - String
- `product` - Integer
- `release_date` - Date
  - Format: `yyyy-mm-dd` (2020-09-30)
- `version` - String
- `release_notes_link` - String
- `eula_link` - String
- `size` - String
  - Digits only
- `requires_version` - String
  - Will be set to oldest existing version if not specified

### Data Example:

```json
{
    "environment": "linux",
    "hash_md5": "96962fd22cae41c54a3622ea79cd2bf8",
    "full_link": "http://www.africau.edu/images/default/sample.pdf",
    "product": 1584723961091256,
    "release_date": "2020-11-04",
    "version": "ver1.7",
    "release_notes_link": "http://www.africau.edu/images/default/sample.pdf",
    "eula_link": "http://www.africau.edu/images/default/sample.pdf",
    "size": "123",
    "requires_version": "ver1.5"
}
```

### Success Response:

**Code**: `200 OK`

**Content Examples:**

```json
{
    "id": 733293,
    "created_at": "2020-11-05T12:56:15.825459Z",
    "updated_at": "2020-11-05T12:56:15.825514Z",
    "version": "ver1.7",
    "full_link": "http://www.africau.edu/images/default/sample.pdf",
    "filename": "sample.pdf",
    "release_date": "2020-11-04",
    "enabled": true,
    "hash_md5": "96962fd22cae41c54a3622ea79cd2bf8",
    "environment": "linux",
    "release_notes_link": "http://www.africau.edu/images/default/sample.pdf",
    "eula_link": "http://www.africau.edu/images/default/sample.pdf",
    "size": "123",
    "requires_version": "ver1.5",
    "product": 1584723961091256
}
```


[title] Import License Features From CSV
[path] Management API/License/

Imports license features from csv if requesting manager has access permissions to it.

:::hint{type="warning"}
Ensure that all text fields in your CSV use **ASCII characters**. Non-ASCII characters (such as “ä”, “ñ”, or other special symbols) can cause import errors. To avoid issues, remove or replace these characters before uploading your file.
:::

**URL** : `/api/v1/licenses/import_features_from_csv/`

**Method** : `POST`

### Content-Type

Required `Content-Type` is `multipart/form-data` with the following single key value pair:

- Key: `file`
- Value: `{csv file from which to import}`

### Required CSV Headers

- `license_key`
- `code`

### Possible CSV Headers

- `max_consumption`
- `total_consumptions`
- `expiry_date`
- `allow_overages`
- `consumption_period`
- `max_overages`
- `reset_consumption`

### Data example

```csv
license_key,code,max_consumption,expiry_date,allow_overages,consumption_period,max_overages,reset_consumption
GF32-XR78-JA2K-LYBU,f1,,,,,,
GF32-XR78-JA2K-LYBU,f2,10,,0,,,0
GF32-XR78-JA2K-LYBU,f3,,,,,,
GF32-XR78-J4EK-LYBU,f3,,2021-09-09,,,,
GF32-XR78-J4EK-LYBU,f4,100,,1,daily,10,1
```

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{
    "job_id": 10
}
```

`job_id` from response can be used to query the import result.

[title] List License Custom Fields
[path] Management API/License/Custom Fields/

Show all license custom fields the requesting manager has access permissions to.

**URL**: `/api/v1/license-custom-fields/`

**Method**: `GET`

### Query Parameters:

### Pagination:

Default pagina
tion is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on license custom field or related to the license custom field.

Possible filters:

- `license`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "count": 2,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 78,
            "value": "23",
            "license": 1609234933166159,
            "product_custom_field": 51
        }
        ...
    ]
}
```


[title] List License User Group managers
[path] Management API/License/User Groups/

Show all license user group managers.

**URL** : `/api/v1/license-user-groups/{id}/managers/`

**Method** : `GET`

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
[
    {
        "id": 3420,
        "true_email": "example@gmail.com",
        "is_initial_password": true,
        "initial_password": "test1234",
        "first_name": "First 1",
        "last_name": "Last 1",
        "phone_number": ""
    }
]
```


[title] Delete License User Group
[path] Management API/License/User Groups/

Delete a single license user group.

**URL** : `/api/v1/license-user-groups/{id}/`

**Method** : `DELETE`

### Success Response

**Code** : `204 No Content`

[title] Create License Custom Field
[path] Management API/License/Custom Fields/

Creates a license custom field, if requesting manager has access permissions to it.

**URL**: `/api/v1/license-custom-fields/`

**Method**: `POST`

### Parameters:

- `value` - String
- `license` - Integer
- `product_custom_field` - Integer

### Data Example:

```json
{
    "value": "23",
    "license": 1609234933166159,
    "product_custom_field": 51
}
```

### Success Response:

**Code**: `201 OK`

**Content Examples**:

```json
{
    "id": 83,
    "value": "23",
    "license": 1609234933166159,
    "product_custom_field": 51
}
```


[title] Remove License User from License User Group
[path] Management API/License/Users/

Removes a license user from a license user group.

**URL** : `/api/v1/license-users/{id}/remove_from_group/`

**Method** : `POST`

### Data example

```json
{
    "license_user_group_id": 2
}
```

### Success Response

**Code** : `200 OK`

[title] Update License Product Features
[path] Management API/License/

Updates product features on a license if requesting manager has access permissions to it.

**URL**: `/api/v1/licenses/{id}/update_features/`

**Method**: `POST`

- License product features provided in `product_features` list will be created if not on License or updated if already on License.
- License product features already on license but not provided in `product_features` list will be deleted from License.

### Parameters for Each License Product Feature:

- `product_feature` - String
- `max_consumption` - Integer
- `total_consumptions` - Integer
- `expiry_date` - Date
  - Format: `yyyy-mm-dd` (2020-09-30)
- `allow_overages` - Boolean
- `max_overages` - Integer
- `reset_consumption` - Boolean
- `consumption_period` - String
  - Choices: `daily`, `weekly`, `monthly`, `annualy`
- `metadata` - JSON
- `is_floating` - Boolean
- `is_floating_cloud `-Boolean
- `floating_users` - Integer
- `floating_timeout` - Integer



### Data Example:

```json
{
    "product_features": [
        {
            "product_feature": "f5"
        },
        {
            "product_feature": "f2",
            "max_consumption": 88,
            "total_consumptions": 0
        }
    ]
}
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 1593781720493289,
    "status": "Inactive",
    "floating_in_use_devices": 0,
    "customer": {
        "id": 620,
        "total_orders": 14,
        "total_licenses": 45,
        "labels": [
            {
                "id": 3,
                "label_id": 8,
                "label": "Customer",
                "color": "#ff9f43"
            },
            {
                "id": 53,
                "label_id": 34,
                "label": "Loyal",
                "color": "#3a0cd4"
            }
        ],
        "email": "tc@tc.com",
        "first_name": "",
        "last_name": "",
        "company_name": "",
        "phone": "",
        "reference": "",
        "address": "",
        "postcode": "",
        "city": "",
        "country": "",
        "state": "",
        "clabels_all": "customerloyal",
        "cognito_user_pool_id": "",
        "metadata": {},
        "company": 277,
        "license_user": null,
        "clabels": [
            8,
            34
        ]
    },
    "product_features": [
        {
            "id": 1605023917125630,
            "product_feature": {
                "id": 189,
                "created_at": "2020-11-13T07:40:53Z",
                "updated_at": "2020-11-13T07:40:53Z",
                "name": "Feature 5",
                "code": "f5",
                "is_deleted": false,
                "feature_type": "activation",
                "max_consumption": 0,
                "allow_overages": false,
                "max_overages": 0,
                "reset_consumption": false,
                "consumption_period": null,,
                "metadata": {}
            },
            "max_consumption": 0,
            "total_consumptions": 0,
            "expiry_date": null,
            "allow_overages": false,
            "max_overages": 99,
            "reset_consumption": false,
            "consumption_period": null,
            "metadata": {}
        },
        {
            "id": 1605023917125631,
            "product_feature": {
                "id": 172,
                "created_at": "2020-08-26T05:37:14Z",
                "updated_at": "2020-08-26T05:37:14Z",
                "name": "Feature 2",
                "code": "f2",
                "is_deleted": false,
                "feature_type": "consumption",
                "max_consumption": 20,
                "allow_overages": false,
                "max_overages": 0,
                "reset_consumption": false,
                "consumption_period": null,
                "metadata": {}
            },
            "max_consumption": 88,
            "total_consumptions": 0,
            "expiry_date": null,
            "allow_overages": false,
            "max_overages": 99,
            "reset_consumption": false,
            "consumption_period": null,
            "metadata": {}
        }
    ],
    "product_custom_fields": [],
    "license_users": [
        {
            "id": 1240,
            "last_login": null,
            "email": "example@email.com|uss1",
            "true_email": "example@email.com",
            "created_at": "2020-08-12T08:52:32Z",
            "updated_at": "2020-08-12T09:01:24Z",
            "is_admin": {},
            "is_active": true,
            "is_staff": false,
            "first_name": "John",
            "last_name": "Doe",
            "phone_number": "00385913109161",
            "subscribed_to_email": false,
            "acquired_consent": null,
            "is_manager": false,
            "initial_password": "4q3dg7!_",
            "is_initial_password": true
        }
    ],
    "order_store_id": "d2d2dce02c844d4492c9d48758aa143a",
    "active_up_to_date_devices": 0,
    "total_active_devices": 0,
    "product": {
        "id": 1584723961091234,
        "product_name": "mch"
    },
    "created_at": "2020-07-03T13:08:40Z",
    "updated_at": "2020-11-13T07:41:01.671067Z",
    "license_key": null,
    "active": false,
    "enabled": true,
    "time_activated": "2020-10-10T14:42:16Z",
    "time_disabled": "2020-08-14T07:26:27Z",
    "max_activations": 5,
    "times_activated": 0,
    "valid_duration": null,
    "validity_period": "2020-09-30",
    "license_type": "perpetual",
    "enable_maintenance_period": true,
    "maintenance_duration": "3m",
    "maintenance_period": "2021-01-10",
    "is_trial": true,
    "max_consumptions": 0,
    "total_consumptions": 0,
    "subscription_id": null,
    "last_check": null,
    "prevent_vm": true,
    "allow_overages": false,
    "max_overages": 0,
    "reset_consumption": false,
    "consumption_period": null,
    "trial_days": 0,
    "is_floating": false,
    "is_floating_cloud": true,
    "floating_users": 1,
    "note": null,
    "max_license_users": 0,
    "transfer_count": 0,
    "floating_timeout": null,
    "max_transfers": 0,
    "is_air_gapped": false,
    "can_borrow": false,
    "max_borrow_time": 0,
    "is_bundle": false,
    "metadata": {},
    "order": 1593781720493279,
    "order_item": 1593781720493299,
    "disabled_user": null,
    "last_activation_device": null
}
```


[title] Delete License User
[path] Management API/License/Users/

Delete a single license user if requesting manager has access permissions to it.

**URL** : `/api/v1/license-users/{id}/`

**Method** : `DELETE`

### Success Response

**Code** : `204 No Content`

[title] Release Device From License Product Feature
[path] Management API/License/ Features/

Releases device from a license product feature.

**URL**: `/api/v1/license-product-features/{id}/release_device/`

**Method**: `POST`

## Data example

```json
{
    "device":"device_id"
}
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "detail": "Device released."
}
```


[title] Remove License Manager Permissions
[path] Management API/License/Managers/

Removes permissions for a single license manager if requesting manager has access permissions to it.

**URL** : `/api/v1/license-users/{id}/remove_lm_permissions/`

**Method** : `POST`

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{}
```


[title] Update License User
[path] Management API/License/Users/

Updates a license user, if requesting manager has access permissions to it.

**URL**: `/api/v1/license-users/{id}/`

**Method**: `PATCH`

### Parameters:

- `first_name` - String
- `last_name` - String
- `phone_number` - String
- `metadata` - JSON

### Data Example:

```json
{
    "first_name": "Harry"
}
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 2270,
    "last_login": null,
    "email": "end-user@gmail.com|tn",
    "true_email": "end-user@gmail.com",
    "created_at": "2021-08-24T07:22:27Z",
    "updated_at": "2021-10-14T08:11:39.085690Z",
    "is_active": true,
    "is_manager": false,
    "initial_password": "5dH7Oqfq",
    "is_initial_password": true,
    "first_name": "Harry",
    "last_name": "sre",
    "phone_number": "123"
}
```


[title] License
[path] Management API/


[title] Export Orders
[path] Management API/Order/

:::ApiMethodV2
```json
{
  "name": " Export multiple orders to csv, if requesting manager has access permissions to them.",
  "method": "GET",
  "url": "/api/v1/orders/export/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "XW9WyokrOS_fpVO8rMbQZ",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "XW9WyokrOS_fpVO8rMbQZ"
  },
  "results": {
    "languages": [
      {
        "id": "qUCD9-tNNjniqCZ5_VNM8",
        "language": "200",
        "code": "\"order__id\",\"order__created_at\",\"order__reference\",\"order__store_id\",\"order__type\",\"customer__first_name\",\"customer__last_name\",\"customer__email\",\"customer__company_name\",\"customer__phone\",\"customer__reference\",\"customer__address\",\"customer__postcode\",\"customer__state\",\"customer__city\",\"customer__country\",\"license__id\",\"license__license_key\",\"license__created_at\",\"license__updated_at\",\"license__license_type\",\"license__time_activated\",\"license__max_activations\",\"license__allow_unlimited_activations\",\"license__times_activated\",\"license__active\",\"license__features\",\"license__prevent_vm\",\"license__valid_duration\",\"license__validity_period\",\"license__max_consumptions\",\"license__total_consumptions\",\"license__subscription_id\",\"license__last_check\",\"license__allow_overages\",\"license__max_overages\",\"license__reset_consumption\",\"license__consumption_period\",\"license__user_emails\",\"license__custom_fields\",\"license__start_date\",\"license__is_air_gapped\",\"license__is_trial\",\"license__is_floating\",\"license__is_floating_cloud\",\"license__floating_users\",\"license__enable_maintenance_period\",\"license__maintenance_duration\",\"license__maintenance_period\",\"license__note\",\"license__max_transfers\",\"license__floating_timeout\",\"license__enabled\",\"license__allow_unlimited_consumptions\",\"license__allow_negative_consumptions\",\"license__time_disabled\",\"license__trial_days\",\"license__max_license_users\",\"license__transfer_count\",\"license__can_borrow\",\"license__max_borrow_time\",\"license__is_bundle\",\"license__allow_grace_period\",\"license__grace_period\",\"license__is_hardware_key_auth\",\"product__name\",\"product__short_code\"\n1737376048863009,\"2025-01-20 12:27:29+00:00\",\"\",\"61e739b799dc49ddb8cc731f52fd9692\",\"bundle\",\"A\",\"J\",\"antonio.jovanovic@licensespring.com\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",1737376049165029,\"5MA7-KN6Q-TJUY-PKTP\",\"2025-01-20 12:27:29+00:00\",\"2025-01-20 13:21:28+00:00\",\"perpetual\",\"2025-01-20 13:21:28+00:00\",1,False,1,True,\"\",False,\"\",\"\",\"\",0,\"\",\"2025-01-27 13:12:55+00:00\",False,0,False,\"\",\"\",\"\",\"\",False,False,False,False,1,False,\"\",\"\",\"\",0,120,True,False,True,\"\",15,1,0,False,0,True,False,0,False,\"tp\",\"tp\"\n1737376048863009,\"2025-01-20 12:27:29+00:00\",\"\",\"61e739b799dc49ddb8cc731f52fd9692\",\"bundle\",\"A\",\"J\",\"antonio.jovanovic@licensespring.com\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",1737376049260039,\"\",\"2025-01-20 12:27:29+00:00\",\"2025-01-20 13:26:57+00:00\",\"perpetual\",\"2025-01-20 13:26:57+00:00\",2,False,1,True,\"\",False,\"\",\"\",\"\",0,\"\",\"2025-01-20 15:23:52+00:00\",False,0,False,\"\",\"\",\"custom_field=some default value\",\"\",False,False,False,False,1,False,\"\",\"\",\"\",0,1,True,False,True,\"\",15,1,0,False,0,False,False,0,False,\"Basic product\",\"basicproduct\"",
        "customLabel": ""
      },
      {
        "id": "zmoZaRF0p2qmdXIuLO7rE",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "qUCD9-tNNjniqCZ5_VNM8"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "export-multiple-orders-to-csv-if-requesting-manage",
  "legacyHash": "zmpa-GKs55u3lJhRlDrAD"
}
```
:::

### Query Parameters:

### Period:

Either `range` or (`from` and `to`) query parameters are required.

- `range` - Orders created in last number of days specified.
  - Valid values: `last30`, `last60`, `last180`, `last365`
  - Example: `range=last30`
- `from` - Orders created after this date.
  - Format: `YYYY-MM-DD`
  - Example: `from=2020-07-04`
- `to` - Orders created before this date.
  - Format: `YYYY-MM-DD`
  - Example: `to=2020-07-10`


[title] Retrieve Order
[path] Management API/Order/

:::ApiMethodV2
```json
{
  "name": "Retrieve a single order, if requesting manager has access permissions to it.",
  "method": "GET",
  "url": "/api/v1/orders/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "XD7NnObp3XlaMwE0Vv9Mv",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "XD7NnObp3XlaMwE0Vv9Mv"
  },
  "results": {
    "languages": [
      {
        "id": "DiReK3r3bl1fQF2OYT5xQ",
        "language": "200",
        "code": "{\n    \"id\": 1593781720493279,\n    \"order_items\": [\n        {\n            \"id\": 1593781720493299,\n            \"product_id\": 1584723961091234,\n            \"licenses\": [\n                {\n                    \"id\": 1593781720493289,\n                    \"customer\": {\n                        \"id\": 620,\n                        \"total_orders\": 14,\n                        \"total_licenses\": 45,\n                        \"labels\": [\n                            {\n                                \"id\": 3,\n                                \"label_id\": 8,\n                                \"label\": \"Customer\",\n                                \"color\": \"#ff9f43\"\n                            },\n                            {\n                                \"id\": 53,\n                                \"label_id\": 34,\n                                \"label\": \"Loyal\",\n                                \"color\": \"#3a0cd4\"\n                            }\n                        ],\n                        \"email\": \"tc@tc.com\",\n                        \"first_name\": \"\",\n                        \"last_name\": \"\",\n                        \"company_name\": \"\",\n                        \"phone\": \"\",\n                        \"reference\": \"\",\n                        \"address\": \"\",\n                        \"postcode\": \"\",\n                        \"city\": \"\",\n                        \"country\": \"\",\n                        \"state\": \"\",\n                        \"clabels_all\": \"customerloyal\",\n                        \"cognito_user_pool_id\": \"\",\n                        \"metadata\": {},\n                        \"company\": 277,\n                        \"license_user\": null,\n                        \"clabels\": [\n                            8,\n                            34\n                        ]\n                    },\n                    \"product_features\": [\n                        {\n                            \"id\": 1605023917125630,\n                            \"product_feature\": {\n                                \"id\": 189,\n                                \"created_at\": \"2020-11-13T07:40:53Z\",\n                                \"updated_at\": \"2020-11-13T07:40:53Z\",\n                                \"name\": \"Feature 5\",\n                                \"code\": \"f5\",\n                                \"is_deleted\": false,\n                                \"feature_type\": \"activation\",\n                                \"max_consumption\": 0,\n                                \"allow_overages\": false,\n                                \"max_overages\": 0,\n                                \"reset_consumption\": false,\n                                \"consumption_period\": null,\n                                \"metadata\": {}\n                            },\n                            \"max_consumption\": 0,\n                            \"total_consumptions\": 0,\n                            \"expiry_date\": null,\n                            \"allow_overages\": false,\n                            \"max_overages\": 99,\n                            \"reset_consumption\": false,\n                            \"consumption_period\": null,\n                            \"metadata\": {}\n                        },\n                        {\n                            \"id\": 1605023917125631,\n                            \"product_feature\": {\n                                \"id\": 172,\n                                \"created_at\": \"2020-08-26T05:37:14Z\",\n                                \"updated_at\": \"2020-08-26T05:37:14Z\",\n                                \"name\": \"Feature 2\",\n                                \"code\": \"f2\",\n                                \"is_deleted\": false,\n                                \"feature_type\": \"consumption\",\n                                \"max_consumption\": 20,\n                                \"allow_overages\": false,\n                                \"max_overages\": 0,\n                                \"reset_consumption\": false,\n                                \"consumption_period\": null,\n                                \"metadata\": {}\n                            },\n                            \"max_consumption\": 5,\n                            \"total_consumptions\": 0,\n                            \"expiry_date\": null,\n                            \"allow_overages\": false,\n                            \"max_overages\": 99,\n                            \"reset_consumption\": false,\n                            \"consumption_period\": null,\n                            \"metadata\": {}\n                        }\n                    ],\n                    \"product_custom_fields\": [],\n                    \"license_user\": {\n                        \"id\": 1240,\n                        \"last_login\": null,\n                        \"email\": \"example@email.com|uss1\",\n                        \"true_email\": \"example@email.com\",\n                        \"created_at\": \"2020-08-12T08:52:32Z\",\n                        \"updated_at\": \"2020-08-12T09:01:24Z\",\n                        \"is_admin\": {},\n                        \"is_active\": true,\n                        \"is_staff\": false,\n                        \"first_name\": \"John\",\n                        \"last_name\": \"Doe\",\n                        \"phone_number\": \"00385913109161\",\n                        \"subscribed_to_email\": false,\n                        \"acquired_consent\": null,\n                        \"is_manager\": false,\n                        \"initial_password\": \"4q3dg7!_\",\n                        \"is_initial_password\": true\n                    },\n                    \"license_users\": [\n                        {\n                            \"id\": 1240,\n                            \"last_login\": null,\n                            \"email\": \"example@email.com|uss1\",\n                            \"true_email\": \"example@email.com\",\n                            \"created_at\": \"2020-08-12T08:52:32Z\",\n                            \"updated_at\": \"2020-08-12T09:01:24Z\",\n                            \"is_admin\": {},\n                            \"is_active\": true,\n                            \"is_staff\": false,\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"phone_number\": \"00385913109161\",\n                            \"subscribed_to_email\": false,\n                            \"acquired_consent\": null,\n                            \"is_manager\": false,\n                            \"initial_password\": \"4q3dg7!_\",\n                            \"is_initial_password\": true\n                        }\n                    ],\n                    \"order_store_id\": \"d2d2dce02c844d4492c9d48758aa143a\",\n                    \"active_up_to_date_devices\": 0,\n                    \"product\": {\n                        \"id\": 1584723961091234,\n                        \"short_code\": \"code1\",\n                        \"product_name\": \"mch\"\n                    },\n                    \"created_at\": \"2020-07-03T13:08:40Z\",\n                    \"updated_at\": \"2020-11-13T07:42:58Z\",\n                    \"license_key\": null,\n                    \"active\": false,\n                    \"enabled\": true,\n                    \"time_activated\": \"2020-10-10T14:42:16Z\",\n                    \"time_disabled\": \"2020-08-14T07:26:27Z\",\n                    \"max_activations\": 5,\n                    \"times_activated\": 0,\n                    \"valid_duration\": null,\n                    \"validity_period\": \"2020-09-30\",\n                    \"license_type\": \"perpetual\",\n                    \"enable_maintenance_period\": true,\n                    \"maintenance_duration\": \"3m\",\n                    \"maintenance_period\": \"2021-01-10\",\n                    \"is_trial\": true,\n                    \"max_consumptions\": 0,\n                    \"total_consumptions\": 0,\n                    \"subscription_id\": null,\n                    \"last_check\": null,\n                    \"prevent_vm\": true,\n                    \"allow_overages\": false,\n                    \"max_overages\": 0,\n                    \"reset_consumption\": false,\n                    \"consumption_period\": null,\n                    \"trial_days\": 0,\n                    \"is_floating\": false,\n                    \"is_floating_cloud\": true,\n                    \"floating_users\": 1,\n                    \"note\": null,\n                    \"max_license_users\": 0,\n                    \"transfer_count\": 0,\n                    \"floating_timeout\": null,\n                    \"max_transfers\": 0,\n                    \"is_air_gapped\": false,\n                    \"can_borrow\": false,\n                    \"max_borrow_time\": 0,\n                    \"is_bundle\": false,\n                    \"metadata\": {},\n                    \"order\": 1593781720493279,\n                    \"order_item\": 1593781720493299,\n                    \"disabled_user\": null,\n                    \"last_activation_device\": null,\n                    \"status\": \"Inactive\"\n                }\n            ],\n            \"created_at\": null,\n            \"updated_at\": null,\n            \"order\": 1593781720493279,\n            \"product\": 1584723961091234\n        }\n    ],\n    \"customer\": {\n        \"id\": 620,\n        \"total_orders\": 14,\n        \"total_licenses\": 45,\n        \"labels\": [\n            {\n                \"id\": 3,\n                \"label_id\": 8,\n                \"label\": \"Customer\",\n                \"color\": \"#ff9f43\"\n            },\n            {\n                \"id\": 53,\n                \"label_id\": 34,\n                \"label\": \"Loyal\",\n                \"color\": \"#3a0cd4\"\n            }\n        ],\n        \"customer_account\": null,\n        \"email\": \"tc@tc.com\",\n        \"first_name\": \"\",\n        \"last_name\": \"\",\n        \"company_name\": \"\",\n        \"phone\": \"\",\n        \"reference\": \"\",\n        \"address\": \"\",\n        \"postcode\": \"\",\n        \"city\": \"\",\n        \"country\": \"\",\n        \"state\": \"\",\n        \"clabels_all\": \"customerloyal\",\n        \"cognito_user_pool_id\": \"\",\n        \"metadata\": {},\n        \"company\": 277,\n        \"license_user\": null,\n        \"clabels\": [\n            8,\n            34\n        ]\n    },\n    \"has_active_licenses\": false,\n    \"created_at\": \"2020-07-03T13:08:40Z\",\n    \"updated_at\": \"2020-07-03T13:08:40Z\",\n    \"store_id\": \"d2d2dce02c844d4492c9d48758aa143a\",\n    \"type\": \"normal\",\n    \"customer_email\": null,\n    \"is_test\": false,\n    \"customer_reference\": null,\n    \"is_trial\": false,\n    \"download_id\": null,\n    \"language\": null,\n    \"campaign_params\": null,\n    \"customer_first_name\": null,\n    \"customer_last_name\": null,\n    \"customer_company\": null,\n    \"customer_phone\": null,\n            \"metadata\": {},\n    \"company\": 277\n}{\n    \"id\": 1593781720493279,\n    \"order_items\": [\n        {\n            \"id\": 1593781720493299,\n            \"product_id\": 1584723961091234,\n            \"licenses\": [\n                {\n                    \"id\": 1593781720493289,\n                    \"customer\": {\n                        \"id\": 620,\n                        \"total_orders\": 14,\n                        \"total_licenses\": 45,\n                        \"labels\": [\n                            {\n                                \"id\": 3,\n                                \"label_id\": 8,\n                                \"label\": \"Customer\",\n                                \"color\": \"#ff9f43\"\n                            },\n                            {\n                                \"id\": 53,\n                                \"label_id\": 34,\n                                \"label\": \"Loyal\",\n                                \"color\": \"#3a0cd4\"\n                            }\n                        ],\n                        \"email\": \"tc@tc.com\",\n                        \"first_name\": \"\",\n                        \"last_name\": \"\",\n                        \"company_name\": \"\",\n                        \"phone\": \"\",\n                        \"reference\": \"\",\n                        \"address\": \"\",\n                        \"postcode\": \"\",\n                        \"city\": \"\",\n                        \"country\": \"\",\n                        \"state\": \"\",\n                        \"clabels_all\": \"customerloyal\",\n                        \"cognito_user_pool_id\": \"\",\n                        \"metadata\": {},\n                        \"company\": 277,\n                        \"license_user\": null,\n                        \"clabels\": [\n                            8,\n                            34\n                        ]\n                    },\n                    \"product_features\": [\n                        {\n                            \"id\": 1605023917125630,\n                            \"product_feature\": {\n                                \"id\": 189,\n                                \"created_at\": \"2020-11-13T07:40:53Z\",\n                                \"updated_at\": \"2020-11-13T07:40:53Z\",\n                                \"name\": \"Feature 5\",\n                                \"code\": \"f5\",\n                                \"is_deleted\": false,\n                                \"feature_type\": \"activation\",\n                                \"max_consumption\": 0,\n                                \"allow_overages\": false,\n                                \"max_overages\": 0,\n                                \"reset_consumption\": false,\n                                \"consumption_period\": null,\n                                \"metadata\": {}\n                            },\n                            \"max_consumption\": 0,\n                            \"total_consumptions\": 0,\n                            \"expiry_date\": null,\n                            \"allow_overages\": false,\n                            \"max_overages\": 99,\n                            \"reset_consumption\": false,\n                            \"consumption_period\": null,\n                            \"metadata\": {}\n                        },\n                        {\n                            \"id\": 1605023917125631,\n                            \"product_feature\": {\n                                \"id\": 172,\n                                \"created_at\": \"2020-08-26T05:37:14Z\",\n                                \"updated_at\": \"2020-08-26T05:37:14Z\",\n                                \"name\": \"Feature 2\",\n                                \"code\": \"f2\",\n                                \"is_deleted\": false,\n                                \"feature_type\": \"consumption\",\n                                \"max_consumption\": 20,\n                                \"allow_overages\": false,\n                                \"max_overages\": 0,\n                                \"reset_consumption\": false,\n                                \"consumption_period\": null,\n                                \"metadata\": {}\n                            },\n                            \"max_consumption\": 5,\n                            \"total_consumptions\": 0,\n                            \"expiry_date\": null,\n                            \"allow_overages\": false,\n                            \"max_overages\": 99,\n                            \"reset_consumption\": false,\n                            \"consumption_period\": null,\n                            \"metadata\": {}\n                        }\n                    ],\n                    \"product_custom_fields\": [],\n                    \"license_user\": {\n                        \"id\": 1240,\n                        \"last_login\": null,\n                        \"email\": \"example@email.com|uss1\",\n                        \"true_email\": \"example@email.com\",\n                        \"created_at\": \"2020-08-12T08:52:32Z\",\n                        \"updated_at\": \"2020-08-12T09:01:24Z\",\n                        \"is_admin\": {},\n                        \"is_active\": true,\n                        \"is_staff\": false,\n                        \"first_name\": \"John\",\n                        \"last_name\": \"Doe\",\n                        \"phone_number\": \"00385913109161\",\n                        \"subscribed_to_email\": false,\n                        \"acquired_consent\": null,\n                        \"is_manager\": false,\n                        \"initial_password\": \"4q3dg7!_\",\n                        \"is_initial_password\": true\n                    },\n                    \"license_users\": [\n                        {\n                            \"id\": 1240,\n                            \"last_login\": null,\n                            \"email\": \"example@email.com|uss1\",\n                            \"true_email\": \"example@email.com\",\n                            \"created_at\": \"2020-08-12T08:52:32Z\",\n                            \"updated_at\": \"2020-08-12T09:01:24Z\",\n                            \"is_admin\": {},\n                            \"is_active\": true,\n                            \"is_staff\": false,\n                            \"first_name\": \"John\",\n                            \"last_name\": \"Doe\",\n                            \"phone_number\": \"00385913109161\",\n                            \"subscribed_to_email\": false,\n                            \"acquired_consent\": null,\n                            \"is_manager\": false,\n                            \"initial_password\": \"4q3dg7!_\",\n                            \"is_initial_password\": true\n                        }\n                    ],\n                    \"order_store_id\": \"d2d2dce02c844d4492c9d48758aa143a\",\n                    \"active_up_to_date_devices\": 0,\n                    \"product\": {\n                        \"id\": 1584723961091234,\n                        \"short_code\": \"code1\",\n                        \"product_name\": \"mch\"\n                    },\n                    \"created_at\": \"2020-07-03T13:08:40Z\",\n                    \"updated_at\": \"2020-11-13T07:42:58Z\",\n                    \"license_key\": null,\n                    \"active\": false,\n                    \"enabled\": true,\n                    \"time_activated\": \"2020-10-10T14:42:16Z\",\n                    \"time_disabled\": \"2020-08-14T07:26:27Z\",\n                    \"max_activations\": 5,\n                    \"times_activated\": 0,\n                    \"valid_duration\": null,\n                    \"validity_period\": \"2020-09-30\",\n                    \"license_type\": \"perpetual\",\n                    \"enable_maintenance_period\": true,\n                    \"maintenance_duration\": \"3m\",\n                    \"maintenance_period\": \"2021-01-10\",\n                    \"is_trial\": true,\n                    \"max_consumptions\": 0,\n                    \"total_consumptions\": 0,\n                    \"subscription_id\": null,\n                    \"last_check\": null,\n                    \"prevent_vm\": true,\n                    \"allow_overages\": false,\n                    \"max_overages\": 0,\n                    \"reset_consumption\": false,\n                    \"consumption_period\": null,\n                    \"trial_days\": 0,\n                    \"is_floating\": false,\n                    \"is_floating_cloud\": true,\n                    \"floating_users\": 1,\n                    \"note\": null,\n                    \"max_license_users\": 0,\n                    \"transfer_count\": 0,\n                    \"floating_timeout\": null,\n                    \"max_transfers\": 0,\n                    \"is_air_gapped\": false,\n                    \"can_borrow\": false,\n                    \"max_borrow_time\": 0,\n                    \"is_bundle\": false,\n                    \"metadata\": {},\n                    \"order\": 1593781720493279,\n                    \"order_item\": 1593781720493299,\n                    \"disabled_user\": null,\n                    \"last_activation_device\": null,\n                    \"status\": \"Inactive\"\n                }\n            ],\n            \"created_at\": null,\n            \"updated_at\": null,\n            \"order\": 1593781720493279,\n            \"product\": 1584723961091234\n        }\n    ],\n    \"customer\": {\n        \"id\": 620,\n        \"total_orders\": 14,\n        \"total_licenses\": 45,\n        \"labels\": [\n            {\n                \"id\": 3,\n                \"label_id\": 8,\n                \"label\": \"Customer\",\n                \"color\": \"#ff9f43\"\n            },\n            {\n                \"id\": 53,\n                \"label_id\": 34,\n                \"label\": \"Loyal\",\n                \"color\": \"#3a0cd4\"\n            }\n        ],\n        \"customer_account\": null,\n        \"email\": \"tc@tc.com\",\n        \"first_name\": \"\",\n        \"last_name\": \"\",\n        \"company_name\": \"\",\n        \"phone\": \"\",\n        \"reference\": \"\",\n        \"address\": \"\",\n        \"postcode\": \"\",\n        \"city\": \"\",\n        \"country\": \"\",\n        \"state\": \"\",\n        \"clabels_all\": \"customerloyal\",\n        \"cognito_user_pool_id\": \"\",\n        \"metadata\": {},\n        \"company\": 277,\n        \"license_user\": null,\n        \"clabels\": [\n            8,\n            34\n        ]\n    },\n    \"has_active_licenses\": false,\n    \"created_at\": \"2020-07-03T13:08:40Z\",\n    \"updated_at\": \"2020-07-03T13:08:40Z\",\n    \"store_id\": \"d2d2dce02c844d4492c9d48758aa143a\",\n    \"type\": \"normal\",\n    \"customer_email\": null,\n    \"is_test\": false,\n    \"customer_reference\": null,\n    \"is_trial\": false,\n    \"download_id\": null,\n    \"language\": null,\n    \"campaign_params\": null,\n    \"customer_first_name\": null,\n    \"customer_last_name\": null,\n    \"customer_company\": null,\n    \"customer_phone\": null,\n            \"metadata\": {},\n    \"company\": 277\n}",
        "customLabel": ""
      },
      {
        "id": "FF3pgoczQmEpjQom5W1UV",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "DiReK3r3bl1fQF2OYT5xQ"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "retrieve-a-single-order-if-requesting-manager-has",
  "legacyHash": "6bku0epBGK17teatYoCtf"
}
```
:::


[title] /license-activation-histories/
[path] Management API/License/


[title] Create Order
[path] Management API/Order/

:::ApiMethodV2
```json
{
  "name": "Create order",
  "method": "POST",
  "url": "/api/v1/orders/create_order/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "4AT8zbgAb83PrF3aWtMTP",
        "language": "json",
        "code": "see below",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "4AT8zbgAb83PrF3aWtMTP"
  },
  "results": {
    "languages": [
      {
        "id": "QsVfZCmO2HIKh7DUNC762",
        "language": "200",
        "customLabel": "",
        "code": "see below"
      }
    ],
    "selectedLanguageId": "QsVfZCmO2HIKh7DUNC762"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "id",
        "kind": "required",
        "type": "string",
        "description": "Order ID. This is a unique identifier for an order within a company"
      },
      {
        "name": "is_bundle",
        "kind": "optional",
        "type": "Boolean",
        "description": "If true, defines the order as a bundle order. Defaults to false. For more details on bundle orders, see the Bundle section below",
        "children": []
      },
      {
        "name": "append",
        "kind": "optional",
        "type": "Boolean",
        "description": "If set to true and order ID already exists, licenses (items) sent will be appended to the existing order.\nIf set to false and order ID already exists, an error will be returned.\nIf not set defaults to false.",
        "children": []
      },
      {
        "name": "is_test",
        "kind": "optional",
        "type": "Boolean",
        "description": "Whether or not this is a test order",
        "children": []
      },
      {
        "name": "created",
        "kind": "optional",
        "type": "string",
        "description": "Date and time order is created",
        "children": []
      },
      {
        "name": "order_type",
        "kind": "optional",
        "type": "string",
        "description": "Current possible value is: normal",
        "children": []
      },
      {
        "name": "language",
        "kind": "optional",
        "type": "string",
        "description": "Order language, value should be language short code",
        "children": []
      },
      {
        "name": "campaign_params",
        "kind": "optional",
        "type": "string",
        "description": "e.g. Google campaign params for the order",
        "children": []
      },
      {
        "name": "download_id",
        "kind": "optional",
        "type": "string",
        "description": "Custom order download ID",
        "children": []
      },
      {
        "name": "prevent_vm",
        "kind": "optional",
        "type": "string",
        "description": "If set to true, license activation won't be possible on a Virtual Machine",
        "children": []
      },
      {
        "name": "metadata",
        "kind": "optional",
        "type": "String",
        "description": "Custom metadata, in the format of a serialized JSON object",
        "children": []
      },
      {
        "name": "items",
        "kind": "required",
        "type": "Object",
        "description": "Product licenses in this order\n",
        "children": [
          {
            "name": "product_code",
            "kind": "required",
            "type": "string",
            "description": "Product code to identify the product license order is being created for"
          },
          {
            "name": "licenses",
            "kind": "required",
            "type": "Array",
            "description": "A list of license definitions for this order. See the Licenses section below for more details"
          },
          {
            "name": "note",
            "kind": "optional",
            "type": "string",
            "description": "Item description"
          }
        ]
      },
      {
        "name": "customer",
        "kind": "optional",
        "type": "Object",
        "description": "Customer data for the order",
        "children": [
          {
            "name": "email",
            "kind": "optional",
            "type": "string",
            "description": "customer's email address"
          },
          {
            "name": "first_name",
            "kind": "optional",
            "type": "string",
            "description": "customer's first name"
          },
          {
            "name": "last_name",
            "kind": "optional",
            "type": "string",
            "description": "customer's last name"
          },
          {
            "name": "company",
            "kind": "optional",
            "type": "string",
            "description": "customer's company name"
          },
          {
            "name": "phone",
            "kind": "optional",
            "type": "string",
            "description": "customer's phone number"
          },
          {
            "name": "address",
            "kind": "optional",
            "type": "string",
            "description": "customer's address"
          },
          {
            "name": "reference",
            "kind": "optional",
            "type": "string",
            "description": "customer's custom reference. This can be any identifier for the customer in your system like an UUID."
          },
          {
            "name": "is_manager",
            "kind": "optional",
            "type": "Boolean",
            "description": "if true, customer will be set as manager of licenses in this order"
          }
        ]
      },
      {
        "name": "customer_account_id",
        "kind": "optional",
        "type": "Number",
        "description": "Assignes the order to a Customer Account. If the provided Customer is already assigned to a Customer Account, you can omit this value",
        "children": []
      },
      {
        "name": "add_to_customer_account",
        "kind": "optional",
        "type": "Boolean",
        "description": "Determines whether the Order will be assigned to a Customer Account (defaults to `true`). If you're providing a Customer who is assigned to a Customer Account, but do not wish the Order to be automatically assigned to that same Customer Account, set this parameter to false",
        "children": []
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "create-order",
  "legacyHash": "rzZK5GBEZ_keNNPRV30bw"
}
```
:::

:::hint{type="info"}
**Metadata** should be in literal string format, e.g: `"metadata": "{ \"some_key\": \"some_value\" }"`
:::

## Request

:::hint{type="info"}
The `id` property in the request is a client-generated unique identifier for the request, such as a uuid string
:::

:::hint{type="warning"}
If `append` is set to **true** and no order with the given ID exists, a new order will be created.
:::

### Non-Bundle Order Request

:::CodeblockTabs
```typescript
type RequestSchema = {
  id: string;
  append?: boolean;
  campaign_params?: string;
  created?: string;
  download_id?: string;
  include_metadata_string?: boolean;
  is_test?: boolean;
  language?: string;
  prevent_vm?: boolean;
  add_to_customer_account?: boolean;
  customer?: Customer;
  items: Item[];
}

type Item = {
  active?: boolean;
  customer_account_id?: number;
  key?: string;
  license_policy?: string;
  note?: string;
  product_code: string;
  subscription_id?: string;
  licenses: License[];
}

type Customer = {
  email?: string;
  first_name?: string;
  last_name?: string;
  company_name?: string;
  phone?: string;
  reference?: string;
}

type License = (LicenseWithKey | LicenseWithUsers) & LicenseOptional;

type LicenseWithKey = {
  key?: string;
}

type LicenseWithUsers = {
  users: {
    email: string;
    is_manager?: boolean;
    max_activations?: number;
  }[];
}

type LicenseOptional = {
  active?: boolean,
  allow_grace_period?: boolean,
  allow_negative_consumptions?: boolean,
  allow_overages?: boolean,
  allow_unlimited_activations?: boolean,
  allow_unlimited_consumptions?: boolean,
  can_borrow?: boolean,
  consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually',
  enable_maintenance_period?: boolean,
  enabled?: boolean,
  floating_timeout?: number,
  floating_users?: number,
  grace_period?: number,
  is_air_gapped?: boolean,
  is_floating_cloud?: boolean,
  is_floating?: boolean,
  is_hardware_key_auth?: boolean,
  is_trial?: boolean,
  license_template_code?: string,
  license_template?: number,
  license_type?: LicenseTypes,
  maintenance_duration?: string,
  maintenance_period?: string,
  max_activations?: number,
  max_borrow_time?: number,
  max_consumptions?: number,
  max_license_users?: number,
  max_overages?: number,
  max_transfers?: number,
  metadata?: JSONObjectRequired | null,
  policy_code?: string,
  prevent_vm?: boolean,
  reset_consumption?: boolean,
  start_date?: string,
  subscription_id?: string,
  trial_days?: number,
  valid_duration?: string,
  validity_period?: string,
  custom_fields?: CustomField[],
  product_features?: ProductFeature[],
}

type CustomField = {
  name: string,
  data_type: 'numer' | 'text' | 'date/time',
  value: string | undefined;
};

type ProductFeature = 'string' | {
  code: string,
  allow_overages?: boolean,
  allow_unlimited_consumptions?: boolean,
  allow_negative_consumptions?: boolean,
  consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually',
  expiry_date?: string,
  floating_timeout?: number,
  floating_users?: number,
  is_floating_cloud?: boolean,
  is_floating?: boolean,
  max_consumption?: number,
  max_overages?: number,
  metadata?: JSONObjectRequired,
  reset_consumption?: boolean,
};
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "RequestSchema",
  "type": "object",
  "properties": {
    "id": { "type": "string" },
    "append": { "type": "boolean" },
    "campaign_params": { "type": "string" },
    "created": { "type": "string" },
    "download_id": { "type": "string" },
    "include_metadata_string": { "type": "boolean" },
    "is_test": { "type": "boolean" },
    "language": { "type": "string" },
    "prevent_vm": { "type": "boolean" },
    "add_to_customer_account": { "type": "boolean" },
    "customer": { "$ref": "#/$defs/Customer" },
    "items": {
      "type": "array",
      "items": { "$ref": "#/$defs/Item" }
    }
  },
  "required": [
    "id",
    "items"
  ],
  "additionalProperties": false,
  "$defs": {
    "Customer": {
      "type": "object",
      "properties": {
        "email": { "type": "string" },
        "first_name": { "type": "string" },
        "last_name": { "type": "string" },
        "company_name": { "type": "string" },
        "phone": { "type": "string" },
        "reference": { "type": "string" }
      },
      "additionalProperties": false
    },
    "Item": {
      "type": "object",
      "properties": {
        "active": { "type": "boolean" },
        "customer_account_id": { "type": "number" },
        "key": { "type": "string" },
        "license_policy": { "type": "string" },
        "note": { "type": "string" },
        "product_code": { "type": "string" },
        "subscription_id": { "type": "string" },
        "licenses": {
          "type": "array",
          "items": { "$ref": "#/$defs/License" }
        }
      },
      "required": [
        "product_code",
        "licenses"
      ],
      "additionalProperties": false
    },
    "License": {
      "allOf": [
        {
          "oneOf": [
            { "$ref": "#/$defs/LicenseWithKey" },
            { "$ref": "#/$defs/LicenseWithUsers" }
          ]
        },
        { "$ref": "#/$defs/LicenseOptional" }
      ]
    },
    "LicenseWithKey": {
      "type": "object",
      "properties": {
        "key": { "type": "string" }
      },
      "additionalProperties": false
    },
    "LicenseWithUsers": {
      "type": "object",
      "properties": {
        "users": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "email": { "type": "string" },
              "is_manager": { "type": "boolean" }
            },
            "required": ["email"],
            "additionalProperties": false
          }
        }
      },
      "required": ["users"],
      "additionalProperties": false
    },
    "LicenseOptional": {
      "type": "object",
      "properties": {
        "active": { "type": "boolean" },
        "allow_grace_period": { "type": "boolean" },
        "allow_negative_consumptions": { "type": "boolean" },
        "allow_overages": { "type": "boolean" },
        "allow_unlimited_activations": { "type": "boolean" },
        "allow_unlimited_consumptions": { "type": "boolean" },
        "can_borrow": { "type": "boolean" },
        "consumption_period": { "type": "string", "enum": ["daily","weekly","monthly","annually"] },
        "enable_maintenance_period": { "type": "boolean" },
        "enabled": { "type": "boolean" },
        "floating_timeout": { "type": "number" },
        "floating_users": { "type": "number" },
        "grace_period": { "type": "number" },
        "is_air_gapped": { "type": "boolean" },
        "is_floating_cloud": { "type": "boolean" },
        "is_floating": { "type": "boolean" },
        "is_hardware_key_auth": { "type": "boolean" },
        "is_trial": { "type": "boolean" },
        "license_template_code": { "type": "string" },
        "license_template": { "type": "number" },
        "license_type": { "$ref": "#/$defs/LicenseTypes" },
        "maintenance_duration": { "type": "string" },
        "maintenance_period": { "type": "string" },
        "max_activations": { "type": "number" },
        "max_borrow_time": { "type": "number" },
        "max_consumptions": { "type": "number" },
        "max_license_users": { "type": "number" },
        "max_overages": { "type": "number" },
        "max_transfers": { "type": "number" },
        "metadata": {
          "anyOf": [
            { "$ref": "#/$defs/JSONObjectRequired" },
            { "type": "null" }
          ]
        },
        "policy_code": { "type": "string" },
        "prevent_vm": { "type": "boolean" },
        "reset_consumption": { "type": "boolean" },
        "start_date": { "type": "string" },
        "subscription_id": { "type": "string" },
        "trial_days": { "type": "number" },
        "valid_duration": { "type": "string" },
        "validity_period": { "type": "string" },
        "custom_fields": {
          "type": "array",
          "items": { "$ref": "#/$defs/CustomField" }
        },
        "product_features": {
          "type": "array",
          "items": { "$ref": "#/$defs/ProductFeature" }
        }
      },
      "additionalProperties": false
    },
    "CustomField": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "data_type": { "enum": ["numer", "text", "date/time"] },
        "value": { "type": "string" }
      },
      "required": ["name", "data_type"],
      "additionalProperties": false
    },
    "ProductFeature": {
      "oneOf": [
        { "type": "string", "const": "string" },
        {
          "type": "object",
          "properties": {
            "code": { "type": "string" },
            "allow_overages": { "type": "boolean" },
            "allow_unlimited_consumptions": { "type": "boolean" },
            "allow_negative_consumptions": { "type": "boolean" },
            "consumption_period": { "type": "string", "enum": ["daily","weekly","monthly","annually"] },
            "expiry_date": { "type": "string" },
            "floating_timeout": { "type": "number" },
            "floating_users": { "type": "number" },
            "is_floating_cloud": { "type": "boolean" },
            "is_floating": { "type": "boolean" },
            "max_consumption": { "type": "number" },
            "max_overages": { "type": "number" },
            "metadata": { "$ref": "#/$defs/JSONObjectRequired" },
            "reset_consumption": { "type": "boolean" }
          },
          "required": ["code"],
          "additionalProperties": false
        }
      ]
    },
    "JSONObjectRequired": {
      "type": "object",
      "additionalProperties": true
    },
    "LicenseTypes": {
      "enum": [
        "perpetual",
        "subscription",
        "consumption",
        "time-limited"
      ]
    }
  }
}
```

Example: Key-based license

```json
{
  "id": "id_1546606209296",
  "items": [
    {
      "product_code": "TT",
      "note": "Test 1",  // global note applied to all licenses if no license-level note exists
      "licenses": [
        {
          "key": "123-123-123-123-123",
          "note": "Test 2"  // specific note for this license, overrides global note
        }
      ]
    }
  ]
}

```

Example: User-based license

```json
{
  "id": "id_1546606209296",
  "items": [
    {
      "product_code": "TT",
      "note": "Test 1",  // global note for the product/item
      "licenses": [
        {
          "users": [
            {
              "email": "end-user@gmail.com",
              "is_manager": false
            }
          ],
          "note": "Test 2"  // specific note for this license, overrides global note
        }
      ]
    }
  ]
}

```
:::

### Bundle Order Request

:::CodeblockTabs
```typescript
type Schema = {
  id: string;
  is_bundle: true;
  append?: boolean;
  campaign_params?: string;
  created?: string;
  download_id?: string;
  include_metadata_string?: boolean;
  is_test?: boolean;
  language?: string;
  prevent_vm?: boolean;
  add_to_customer_account?: boolean;
  customer?: Customer | null;
  items: Item[];
}

type Item = {
  active?: boolean;
  customer_account_id?: number;
  key?: string;
  license_policy?: string;
  note?: string;
  product_code: string;
  subscription_id?: string;
  licenses: License[];
}

type Customer = {
  email?: string;
  first_name?: string;
  last_name?: string;
  company_name?: string;
  phone?: string;
  reference?: string;
}

type LicenseWithKey = {
  key?: string;
  license_template_code?: string;
  policy_code: string;
  allow_negative_consumptions?: boolean;
}

type LicenseWithUsers = {
  product_code: string;
  users: {
    email: string;
    is_manager?: boolean;
  }[];
}

type License = (LicenseWithKey | LicenseWithUsers) & LicenseOptional;

type LicenseCommon = {
  active?: boolean,
  allow_grace_period?: boolean,
  allow_negative_consumptions?: boolean,
  allow_overages?: boolean,
  allow_unlimited_activations?: boolean,
  allow_unlimited_consumptions?: boolean,
  can_borrow?: boolean,
  consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually',
  enable_maintenance_period?: boolean,
  enabled?: boolean,
  floating_timeout?: number,
  floating_users?: number,
  grace_period?: number,
  is_air_gapped?: boolean,
  is_floating_cloud?: boolean,
  is_floating?: boolean,
  is_hardware_key_auth?: boolean,
  is_trial?: boolean,
  license_template_code?: string,
  license_template?: number,
  license_type?: LicenseTypes,
  maintenance_duration?: string,
  maintenance_period?: string,
  max_activations?: number,
  max_borrow_time?: number,
  max_consumptions?: number,
  max_license_users?: number,
  max_overages?: number,
  max_transfers?: number,
  metadata?: JSONObjectRequired | null,
  policy_code?: string,
  prevent_vm?: boolean,
  reset_consumption?: boolean,
  start_date?: string,
  subscription_id?: string,
  trial_days?: number,
  valid_duration?: string,
  validity_period?: string,
  custom_fields?: CustomField[],
  product_features?: ProductFeature[],
}

type CustomField = {
  name: string,
  data_type: 'numer' | 'text' | 'date/time',
  value: string | undefined;
};

type ProductFeature = 'string' | {
  code: string,
  allow_overages?: boolean,
  allow_unlimited_consumptions?: boolean,
  allow_negative_consumptions?: boolean,
  consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually',
  expiry_date?: string,
  floating_timeout?: number,
  floating_users?: number,
  is_floating_cloud?: boolean,
  is_floating?: boolean,
  max_consumption?: number,
  max_overages?: number,
  metadata?: JSONObjectRequired,
  reset_consumption?: boolean,
};
```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Schema",
  "type": "object",
  "properties": {
    "id": { "type": "string" },
    "is_bundle": { "const": true },
    "append": { "type": "boolean" },
    "campaign_params": { "type": "string" },
    "created": { "type": "string" },
    "download_id": { "type": "string" },
    "include_metadata_string": { "type": "boolean" },
    "is_test": { "type": "boolean" },
    "language": { "type": "string" },
    "prevent_vm": { "type": "boolean" },
    "add_to_customer_account": { "type": "boolean" },
    "customer": {
      "oneOf": [
        { "$ref": "#/$defs/Customer" },
        { "type": "null" }
      ]
    },
    "items": {
      "type": "array",
      "items": { "$ref": "#/$defs/Item" }
    }
  },
  "required": ["id", "is_bundle", "items"],
  "additionalProperties": false,
  "$defs": {
    "Customer": {
      "type": "object",
      "properties": {
        "email": { "type": "string" },
        "first_name": { "type": "string" },
        "last_name": { "type": "string" },
        "company_name": { "type": "string" },
        "phone": { "type": "string" },
        "reference": { "type": "string" }
      },
      "additionalProperties": false
    },
    "Item": {
      "type": "object",
      "properties": {
        "active": { "type": "boolean" },
        "customer_account_id": { "type": "number" },
        "key": { "type": "string" },
        "license_policy": { "type": "string" },
        "note": { "type": "string" },
        "product_code": { "type": "string" },
        "subscription_id": { "type": "string" },
        "licenses": {
          "type": "array",
          "items": { "$ref": "#/$defs/License" }
        }
      },
      "required": ["product_code", "licenses"],
      "additionalProperties": false
    },
    "License": {
      "allOf": [
        {
          "oneOf": [
            { "$ref": "#/$defs/LicenseWithKey" },
            { "$ref": "#/$defs/LicenseWithUsers" }
          ]
        },
        { "$ref": "#/$defs/LicenseOptional" }
      ]
    },
    "LicenseWithKey": {
      "type": "object",
      "properties": {
        "key": { "type": "string" },
        "license_template_code": { "type": "string" },
        "policy_code": { "type": "string" },
        "allow_negative_consumptions": { "type": "boolean" }
      },
      "required": ["policy_code"],
      "additionalProperties": false
    },
    "LicenseWithUsers": {
      "type": "object",
      "properties": {
        "product_code": { "type": "string" },
        "users": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "email": { "type": "string" },
              "is_manager": { "type": "boolean" }
            },
            "required": ["email"],
            "additionalProperties": false
          }
        }
      },
      "required": ["product_code", "users"],
      "additionalProperties": false
    },
    "LicenseOptional": {
      "type": "object",
      "properties": {
        "active": { "type": "boolean" },
        "allow_grace_period": { "type": "boolean" },
        "allow_negative_consumptions": { "type": "boolean" },
        "allow_overages": { "type": "boolean" },
        "allow_unlimited_activations": { "type": "boolean" },
        "allow_unlimited_consumptions":

```

Example: Key-based bundle

```json
{
  "id": "45gvs334t3edsa",
  "is_bundle": true,
  "items": [
    {
      "product_code": "lkpb",
      "note": "Global note for bundle lkpb",  // global note applied to all licenses if no license-level note exists
      "key": "AAAA-AAAA-AAAA-1130",
      "active": true,
      "subscription_id": 12345,
      "licenses": [
        {
          "product_code": "lkbp1",
          "note": "Note for lkbp1"  // specific note for this license
        },
        {
          "product_code": "lkbp2",
          "note": "Note for lkbp2"  // specific note for this license
        }
      ]
    }
  ]
}

```

Example: User-based bundle

```json
{
  "id": "54yghtref45t",
  "is_bundle": true,
  "items": [
    {
      "product_code": "upb",
      "note": "Global note for bundle upb",  // global note applied to all licenses if no license-level note exists
      "licenses": [
        {
          "active": true,
          "max_activations": 30,
          "product_code": "up",
          "is_trial": false,
          "policy_code": "dftlp",
          "note": "Specific note for this license",  // specific note overrides global note
          "custom_fields": [
            {
              "name": "customField1",
              "value": "abcd"
            }
          ]
        }
      ],
      "users": [
        {
          "email": "someuser@mail.com",
          "is_manager": false
        }
      ]
    }
  ]
}

```
:::

:::hint{type="danger"}
**Notes Overview**

- Global note → applied to all licenses&#x20;
- License-level note → applies only to that license&#x20;
- Both → license-level note takes priority&#x20;
- None → no note field included
:::

## Response

### Non-Bundle Order Response

:::CodeblockTabs
```typescript
type OrderResponse = {
  order_id: string,
  order_items: [
    {
      id: number,
      product_id: number,
      Licenses: License[],
    }
  ],
  new_passwords: { email: string, password: string }[],
}

type License = LicenseCommon & ({
  license_key: string;
  users: never;
  max_license_users: never;
} | {
  license_key: never;
  users: {
    email: string,
    first_name?: string,
    last_name?: string,
    phone_number?: string,
    is_manager: boolean,
  }[];
  max_license_users: number;
}) & ({
  license_type: 'perpetual'
} | {
  license_type: 'subscription';
  allow_grace_period: boolean;
  grace_period: number;
  time_activated: number;
} | {
  license_type: 'consumption';
  allow_negative_consumptions: boolean;
  allow_overages: boolean;
  allow_unlimited_consumptions: boolean;
  consumption_period: string | null;
  max_consumptions: number;
  max_overages: number;
  reset_consumption: boolean;
} | {
  license_type: 'time-limited'
}) & ({
  enable_maintenance_period: false;
} | {
  enable_maintenance_period: true;
  maintenance_duration: string;
  maintenance_period?: string | null;
});

type LicenseCommon = {
  id: number,
  product_id: number,
  active: boolean,
  enabled: true,
  created_at: number,
  updated_at: number,
  license_type: LicenseTypes,
  max_activations: number,
  allow_unlimited_activations: boolean,
  valid_duration: string | null,
  floating_timeout: number,
  max_transfers: number,
  can_borrow: boolean,
  max_borrow_time: number,
  start_date: string | null,
  is_air_gapped: boolean,
  license_template_id: number | null,
  validity_period: string | null,
  subscription_id: string,
  enable_maintenance_period: boolean,
  is_floating_cloud: boolean,
  is_floating: boolean,
  floating_users: number,
  is_trial: boolean,
  trial_days: number,
  prevent_vm: boolean,
  metadata: Record<string, any>,
  is_hardware_key_auth: boolean,
  order_id: number,
  LicenseCustomFields: {
    product_custom_field_id: number;
    value: string | undefined;
  }[],
  LicenseProductFeatures: {
    id: number,
    allow_negative_consumptions: boolean,
    allow_overages: boolean,
    allow_unlimited_consumptions: boolean,
    consumption_period?: string,
    expiry_date: string | null,
    floating_timeout: number,
    floating_users?: number,
    is_floating_cloud?: boolean,
    is_floating?: boolean,
    max_consumption: number,
    max_overages: number,
    metadata: Record<string, any>,
    name?: string,
    product_feature_id: number,
    reset_consumption: boolean,
  }[],
};

enum LicenseTypes {
  perpetual = 'perpetual',
  time_limited = 'time-limited',
  consumption = 'consumption',
  subscription = 'subscription',
};

```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "OrderResponse",
  "type": "object",
  "properties": {
    "order_id": { "type": "string" },
    "order_items": {
      "type": "array",
      "items": { "$ref": "#/$defs/OrderItem" }
    },
    "new_passwords": {
      "type": "array",
      "items": { "$ref": "#/$defs/NewPassword" }
    }
  },
  "required": ["order_id", "order_items", "new_passwords"],
  "additionalProperties": false,
  "$defs": {
    "OrderItem": {
      "type": "object",
      "properties": {
        "id": { "type": "number" },
        "product_id": { "type": "number" },
        "Licenses": {
          "type": "array",
          "items": { "$ref": "#/$defs/License" }
        }
      },
      "required": ["id", "product_id", "Licenses"],
      "additionalProperties": false
    },
    "NewPassword": {
      "type": "object",
      "properties": {
        "email": { "type": "string" },
        "password": { "type": "string" }
      },
      "required": ["email", "password"],
      "additionalProperties": false
    },
    "LicenseCommon": {
      "type": "object",
      "properties": {
        "id": { "type": "number" },
        "product_id": { "type": "number" },
        "active": { "type": "boolean" },
        "enabled": { "const": true },
        "created_at": { "type": "number" },
        "updated_at": { "type": "number" },
        "license_type": {
          "type": "string",
          "enum": ["perpetual", "time-limited", "consumption", "subscription"]
        },
        "max_activations": { "type": "number" },
        "allow_unlimited_activations": { "type": "boolean" },
        "valid_duration": { "type": ["string", "null"] },
        "floating_timeout": { "type": "number" },
        "max_transfers": { "type": "number" },
        "can_borrow": { "type": "boolean" },
        "max_borrow_time": { "type": "number" },
        "start_date": { "type": ["string", "null"] },
        "is_air_gapped": { "type": "boolean" },
        "license_template_id": { "type": ["number", "null"] },
        "validity_period": { "type": ["string", "null"] },
        "subscription_id": { "type": "string" },
        "enable_maintenance_period": { "type": "boolean" },
        "is_floating_cloud": { "type": "boolean" },
        "is_floating": { "type": "boolean" },
        "floating_users": { "type": "number" },
        "is_trial": { "type": "boolean" },
        "trial_days": { "type": "number" },
        "prevent_vm": { "type": "boolean" },
        "metadata": { "type": "object", "additionalProperties": true },
        "is_hardware_key_auth": { "type": "boolean" },
        "order_id": { "type": "number" },
        "LicenseCustomFields": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "product_custom_field_id": { "type": "number" },
              "value": { "type": ["string", "null"] }
            },
            "required": ["product_custom_field_id"],
            "additionalProperties": false
          }
        },
        "LicenseProductFeatures": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": { "type": "number" },
              "allow_negative_consumptions": { "type": "boolean" },
              "allow_overages": { "type": "boolean" },
              "allow_unlimited_consumptions": { "type": "boolean" },
              "consumption_period": { "type": "string" },
              "expiry_date": { "type": ["string", "null"] },
              "floating_timeout": { "type": "number" },
              "floating_users": { "type": "number" },
              "is_floating_cloud": { "type": "boolean" },
              "is_floating": { "type": "boolean" },
              "max_consumption": { "type": "number" },
              "max_overages": { "type": "number" },
              "metadata": { "type": "object", "additionalProperties": true },
              "name": { "type": "string" },
              "product_feature_id": { "type": "number" },
              "reset_consumption": { "type": "boolean" }
            },
            "required": [
              "id",
              "allow_negative_consumptions",
              "allow_overages",
              "allow_unlimited_consumptions",
              "floating_timeout",
              "max_consumption",
              "max_overages",
              "metadata",
              "product_feature_id",
              "reset_consumption"
            ],
            "additionalProperties": false
          }
        }
      },
      "required": [
        "id",
        "product_id",
        "active",
        "enabled",
        "created_at",
        "updated_at",
        "license_type",
        "max_activations",
        "allow_unlimited_activations",
        "valid_duration",
        "floating_timeout",
        "max_transfers",
        "can_borrow",
        "max_borrow_time",
        "start_date",
        "is_air_gapped",
        "license_template_id",
        "validity_period",
        "subscription_id",
        "enable_maintenance_period",
        "is_floating_cloud",
        "is_floating",
        "floating_users",
        "is_trial",
        "trial_days",
        "prevent_vm",
        "metadata",
        "is_hardware_key_auth",
        "order_id",
        "LicenseCustomFields",
        "LicenseProductFeatures"
      ],
      "additionalProperties": false
    },
    "License": {
      "allOf": [
        { "$ref": "#/$defs/LicenseCommon" },
        {
          "oneOf": [
            {
              "type": "object",
              "properties": {
                "license_key": { "type": "string" },
                "users": { "not": {} },
                "max_license_users": { "not": {} }
              },
              "required": ["license_key"],
              "additionalProperties": true
            },
            {
              "type": "object",
              "properties": {
                "users": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "email": { "type": "string" },
                      "first_name": { "type": "string" },
                      "last_name": { "type": "string" },
                      "phone_number": { "type": "string" },
                      "is_manager": { "type": "boolean" }
                    },
                    "required": ["email", "is_manager"],
                    "additionalProperties": false
                  }
                },
                "max_license_users": { "type": "number" },
                "license_key": { "not": {} }
              },
              "required": ["users", "max_license_users"],
              "additionalProperties": true
            }
          ]
        },
        {
          "oneOf": [
            {
              "type": "object",
              "properties": {
                "license_type": { "const": "perpetual" }
              },
              "required": ["license_type"],
              "additionalProperties": true
            },
            {
              "type": "object",
              "properties": {
                "license_type": { "const": "subscription" },
                "allow_grace_period": { "type": "boolean" },
                "grace_period": { "type": "number" },
                "time_activated": { "type": "number" }
              },
              "required": [
                "license_type",
                "allow_grace_period",
                "grace_period",
                "time_activated"
              ],
              "additionalProperties": true
            },
            {
              "type": "object",
              "properties": {
                "license_type": { "const": "consumption" },
                "allow_negative_consumptions": { "type": "boolean" },
                "allow_overages": { "type": "boolean" },
                "allow_unlimited_consumptions": { "type": "boolean" },
                "consumption_period": { "type": ["string", "null"] },
                "max_consumptions": { "type": "number" },
                "max_overages": { "type": "number" },
                "reset_consumption": { "type": "boolean" }
              },
              "required": [
                "license_type",
                "allow_negative_consumptions",
                "allow_overages",
                "allow_unlimited_consumptions",
                "consumption_period",
                "max_consumptions",
                "max_overages",
                "reset_consumption"
              ],
              "additionalProperties": true
            },
            {
              "type": "object",
              "properties": {
                "license_type": { "const": "time-limited" }
              },
              "required": ["license_type"],
              "additionalProperties": true
            }
          ]
        },
        {
          "oneOf": [
            {
              "type": "object",
              "properties": {
                "enable_maintenance_period": { "const": false }
              },
              "required": ["enable_maintenance_period"],
              "additionalProperties": true
            },
            {
              "type": "object",
              "properties": {
                "enable_maintenance_period": { "const": true },
                "maintenance_duration": { "type": "string" },
                "maintenance_period": { "type": ["string", "null"] }
              },
              "required": ["enable_maintenance_period", "maintenance_duration"],
              "additionalProperties": true
            }
          ]
        }
      ]
    }
  }
}

```

Example response

```json
{
  "order_id": "1740411907268009",
  "order_items": [
    {
      "id": "1740411907316029",
      "product_id": 1737539180381356,
      "licenses": [
        {
          "id": "1740411907281019",
          "product_id": 1737539180381356,
          "active": false,
          "enabled": true,
          "created_at": 1740411907285,
          "updated_at": 1740411907285,
          "license_type": "perpetual",
          "max_activations": 1,
          "allow_unlimited_activations": false,
          "valid_duration": null,
          "floating_timeout": 120,
          "max_transfers": 0,
          "can_borrow": false,
          "max_borrow_time": 0,
          "start_date": null,
          "is_air_gapped": false,
          "license_template_id": null,
          "validity_period": null,
          "subscription_id": "",
          "enable_maintenance_period": false,
          "is_floating_cloud": false,
          "is_floating": false,
          "floating_users": 0,
          "is_trial": false,
          "trial_days": 0,
          "prevent_vm": false,
          "metadata": {},
          "is_hardware_key_auth": false,
          "license_key": "B4E5-YAPF-B7YB-SHLK",
          "order_id": "1740411907268009",
          "LicenseProductFeatures": [],
          "LicenseCustomFields": []
        }
      ]
    }
  ],
  "new_passwords": [
    []
  ]
}
```
:::

### Bundle Order Response

:::CodeblockTabs
```typescript
type BundleOrderResponse = {
  order_id: string,
  order_items: [
    {
      id: number,
      product_id: number,
      Licenses: License[],
    }
  ],
  new_passwords: { email: string, password: string }[],
}

type License = BundleLicense | SubLicense;

type BundleLicense = LicenseCommon & {
  order_id: number,
  note?: string,
  is_bundle: true,
  time_activated?: number,
} & ({
  license_key: string;
  users: never;
  max_license_users: never;
} | {
  license_key: never;
  users: {
    email: string,
    first_name?: string,
    last_name?: string,
    phone_number?: string,
    is_manager: boolean,
  }[];
  max_license_users: number;
});

type SubLicense = LicenseCommon & {
  order_id: number,
  note?: string,
  bundle_license_id: number,
  LicenseCustomFields: {
    product_custom_field_id: number;
    value: string | undefined;
  }[],
  LicenseProductFeatures: {
    id: number,
    allow_negative_consumptions: boolean,
    allow_overages: boolean,
    allow_unlimited_consumptions: boolean,
    consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually',
    expiry_date: string | null,
    floating_timeout: number,
    floating_users?: number,
    is_floating_cloud?: boolean,
    is_floating?: boolean,
    max_consumption: number,
    max_overages: number,
    metadata: Record<string, any>,
    name?: string,
    product_feature_id: number,
    reset_consumption: boolean,
  }[],
}

type LicenseCommon = {
  id: number;
  active: boolean;
  allow_unlimited_activations: boolean;
  can_borrow: boolean;
  created_at: number;
  enabled: boolean;
  floating_timeout: number;
  floating_users: number;
  is_air_gapped: boolean;
  is_floating_cloud: boolean;
  is_floating: boolean;
  is_hardware_key_auth: boolean;
  is_trial: boolean;
  license_template_id?: number | null;
  max_activations: number;
  max_borrow_time: number;
  max_transfers: number;
  metadata: Record<string, any>;
  prevent_vm: boolean;
  product_id: number;
  start_date: string | null;
  subscription_id: string;
  trial_days: number;
  updated_at: number;
  valid_duration: string | null;
  validity_period?: string;
} & ({
  license_type: 'perpetual'
} | {
  license_type: 'subscription';
  allow_grace_period: boolean;
  grace_period: number;
  time_activated: number;
} | {
  license_type: 'consumption';
  allow_negative_consumptions: boolean;
  allow_overages: boolean;
  allow_unlimited_consumptions: boolean;
  consumption_period: 'daily' | 'weekly' | 'monthly' | 'annually' | null;
  max_consumptions: number;
  max_overages: number;
  reset_consumption: boolean;
} | {
  license_type: 'time-limited'
}) & ({
  enable_maintenance_period: false;
} | {
  enable_maintenance_period: true;
  maintenance_duration: string;
  maintenance_period?: string | null;
});

enum LicenseTypes {
  perpetual = 'perpetual',
  time_limited = 'time-limited',
  consumption = 'consumption',
  subscription = 'subscription',
};

```

JSON Schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "BundleOrderResponse",
  "type": "object",
  "properties": {
    "order_id": { "type": "string" },
    "order_items": {
      "type": "array",
      "prefixItems": [
        { "$ref": "#/$defs/OrderItem" }
      ],
      "minItems": 1,
      "maxItems": 1
    },
    "new_passwords": {
      "type": "array",
      "items": { "$ref": "#/$defs/NewPassword" }
    }
  },
  "required": [
    "order_id",
    "order_items",
    "new_passwords"
  ],
  "additionalProperties": false,
  "$defs": {
    "OrderItem": {
      "type": "object",
      "properties": {
        "id": { "type": "number" },
        "product_id": { "type": "number" },
        "Licenses": {
          "type": "array",
          "items": { "$ref": "#/$defs/License" }
        }
      },
      "required": [
        "id",
        "product_id",
        "Licenses"
      ],
      "additionalProperties": false
    },
    "NewPassword": {
      "type": "object",
      "properties": {
        "email": { "type": "string" },
        "password": { "type": "string" }
      },
      "required": [
        "email",
        "password"
      ],
      "additionalProperties": false
    },
    "License": {
      "oneOf": [
        { "$ref": "#/$defs/BundleLicense" },
        { "$ref": "#/$defs/SubLicense" }
      ]
    },
    "BundleLicense": {
      "allOf": [
        { "$ref": "#/$defs/LicenseCommon" },
        {
          "type": "object",
          "properties": {
            "order_id": { "type": "number" },
            "note": { "type": "string" },
            "is_bundle": { "const": true },
            "time_activated": { "type": "number" }
          },
          "required": [
            "order_id",
            "is_bundle"
          ],
          "additionalProperties": false
        },
        {
          "oneOf": [
            {
              "type": "object",
              "properties": {
                "license_key": { "type": "string" }
              },
              "required": [
                "license_key"
              ],
              "additionalProperties": false
            },
            {
              "type": "object",
              "properties": {
                "users": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "email": { "type": "string" },
                      "first_name": { "type": "string" },
                      "last_name": { "type": "string" },
                      "phone_number": { "type": "string" },
                      "is_manager": { "type": "boolean" }
                    },
                    "required": [
                      "email",
                      "is_manager"
                    ],
                    "additionalProperties": false
                  }
                },
                "max_license_users": { "type": "number" }
              },
              "required": [
                "users",
                "max_license_users"
              ],
              "additionalProperties": false
            }
          ]
        }
      ]
    },
    "SubLicense": {
      "allOf": [
        { "$ref": "#/$defs/LicenseCommon" },
        {
          "type": "object",
          "properties": {
            "order_id": { "type": "number" },
            "note": { "type": "string" },
            "bundle_license_id": { "type": "number" },
            "LicenseCustomFields": {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "product_custom_field_id": { "type": "number" },
                  "value": { "type": "string" }
                },
                "required": [
                  "product_custom_field_id"
                ],
                "additionalProperties": false
              }
            },
            "LicenseProductFeatures": {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "id": { "type": "number" },
                  "allow_negative_consumptions": { "type": "boolean" },
                  "allow_overages": { "type": "boolean" },
                  "allow_unlimited_consumptions": { "type": "boolean" },
                  "consumption_period": { "type": "string", "enum": ["daily","weekly","monthly","annually"] },
                  "expiry_date": { "type": ["string", "null"] },
                  "floating_timeout": { "type": "number" },
                  "floating_users": { "type": "number" },
                  "is_floating_cloud": { "type": "boolean" },
                  "is_floating": { "type": "boolean" },
                  "max_consumption": { "type": "number" },
                  "max_overages": { "type": "number" },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true
                  },
                  "name": { "type": "string" },
                  "product_feature_id": { "type": "number" },
                  "reset_consumption": { "type": "boolean" }
                },
                "required": [
                  "id",
                  "allow_negative_consumptions",
                  "allow_overages",
                  "allow_unlimited_consumptions",
                  "floating_timeout",
                  "max_consumption",
                  "max_overages",
                  "metadata",
                  "product_feature_id",
                  "reset_consumption"
                ],
                "additionalProperties": false
              }
            }
          },
          "required": [
            "order_id",
            "bundle_license_id",
            "LicenseCustomFields",
            "LicenseProductFeatures"
          ],
          "additionalProperties": false
        }
      ]
    },
    "LicenseCommon": {
      "allOf": [
        {
          "type": "object",
          "properties": {
            "id": { "type": "number" },
            "active": { "type": "boolean" },
            "allow_unlimited_activations": { "type": "boolean" },
            "can_borrow": { "type": "boolean" },
            "created_at": { "type": "number" },
            "enabled": { "type": "boolean" },
            "floating_timeout": { "type": "number" },
            "floating_users": { "type": "number" },
            "is_air_gapped": { "type": "boolean" },
            "is_floating_cloud": { "type": "boolean" },
            "is_floating": { "type": "boolean" },
            "is_hardware_key_auth": { "type": "boolean" },
            "is_trial": { "type": "boolean" },
            "license_template_id": { "type": ["number", "null"] },
            "max_activations": { "type": "number" },
            "max_borrow_time": { "type": "number" },
            "max_transfers": { "type": "number" },
            "metadata": {
              "type": "object",
              "additionalProperties": true
            },
            "prevent_vm": { "type": "boolean" },
            "product_id": { "type": "number" },
            "start_date": { "type": ["string", "null"] },
            "subscription_id": { "type": "string" },
            "trial_days": { "type": "number" },
            "updated_at": { "type": "number" },
            "valid_duration": { "type": ["string", "null"] },
            "validity_period": { "type": "string" }
          },
          "required": [
            "id",
            "active",
            "allow_unlimited_activations",
            "can_borrow",
            "created_at",
            "enabled",
            "floating_timeout",
            "floating_users",
            "is_air_gapped",
            "is_floating_cloud",
            "is_floating",
            "is_hardware_key_auth",
            "is_trial",
            "max_activations",
            "max_borrow_time",
            "max_transfers",
            "metadata",
            "prevent_vm",
            "product_id",
            "start_date",
            "subscription_id",
            "trial_days",
            "updated_at",
            "valid_duration"
          ],
          "additionalProperties": false
        },
        {
          "oneOf": [
            {
              "type": "object",
              "properties": {
                "license_type": { "const": "perpetual" }
              },
              "required": ["license_type"],
              "additionalProperties": true
            },
            {
              "type": "object",
              "properties": {
                "license_type": { "const": "subscription" },
                "allow_grace_period": { "type": "boolean" },
                "grace_period": { "type": "number" },
                "time_activated": { "type": "number" }
              },
              "required": [
                "license_type",
                "allow_grace_period",
                "grace_period",
                "time_activated"
              ],
              "additionalProperties": true
            },
            {
              "type": "object",
              "properties": {
                "license_type": { "const": "consumption" },
                "allow_negative_consumptions": { "type": "boolean" },
                "allow_overages": { "type": "boolean" },
                "allow_unlimited_consumptions": { "type": "boolean" },
                "consumption_period": { "type": ["string", "null"], "enum": ["daily","weekly","monthly","annually",null] },
                "max_consumptions": { "type": "number" },
                "max_overages": { "type": "number" },
                "reset_consumption": { "type": "boolean" }
              },
              "required": [
                "license_type",
                "allow_negative_consumptions",
                "allow_overages",
                "allow_unlimited_consumptions",
                "consumption_period",
                "max_consumptions",
                "max_overages",
                "reset_consumption"
              ],
              "additionalProperties": true
            },
            {
              "type": "object",
              "properties": {
                "license_type": { "const": "time-limited" }
              },
              "required": ["license_type"],
              "additionalProperties": true
            }
          ]
        },
        {
          "oneOf": [
            {
              "type": "object",
              "properties": {
                "enable_maintenance_period": { "const": false }
              },
              "required": ["enable_maintenance_period"],
              "additionalProperties": true
            },
            {
              "type": "object",
              "properties": {
                "enable_maintenance_period": { "const": true },
                "maintenance_duration": { "type": "string" },
                "maintenance_period": { "type": ["string", "null"] }
              },
              "required": [
                "enable_maintenance_period",
                "maintenance_duration"
              ],
              "additionalProperties": true
            }
          ]
        }
      ]
    }
  }
}
```

Example response

```json
{
    "order_id": "1742897553827009",
    "order_items": [
        {
            "id": "1742897554021019",
            "product_id": 4,
            "Licenses": [
                {
                    "id": "1742897554024029",
                    "product_id": 4,
                    "active": false,
                    "enabled": true,
                    "created_at": 1742897554029,
                    "updated_at": 1742897554029,
                    "license_type": "perpetual",
                    "max_activations": 1,
                    "allow_unlimited_activations": false,
                    "valid_duration": null,
                    "floating_timeout": 120,
                    "max_transfers": 0,
                    "can_borrow": false,
                    "max_borrow_time": 0,
                    "start_date": null,
                    "is_air_gapped": false,
                    "license_template_id": null,
                    "validity_period": null,
                    "subscription_id": "",
                    "enable_maintenance_period": false,
                    "is_floating_cloud": false,
                    "is_floating": false,
                    "floating_users": 1,
                    "is_trial": false,
                    "trial_days": 15,
                    "prevent_vm": false,
                    "metadata": {},
                    "is_hardware_key_auth": false,
                    "license_key": "B32M-AXCN-GPEY-CELK",
                    "order_id": "1742897553827009",
                    "is_bundle": true
                },
                {
                    "id": "1742897554109039",
                    "product_id": 1,
                    "active": false,
                    "enabled": true,
                    "created_at": 1742897554112,
                    "updated_at": 1742897554112,
                    "license_type": "perpetual",
                    "max_activations": 1,
                    "allow_unlimited_activations": false,
                    "valid_duration": null,
                    "floating_timeout": 120,
                    "max_transfers": 0,
                    "can_borrow": false,
                    "max_borrow_time": 0,
                    "start_date": null,
                    "is_air_gapped": false,
                    "license_template_id": null,
                    "validity_period": null,
                    "subscription_id": "",
                    "enable_maintenance_period": false,
                    "is_floating_cloud": false,
                    "is_floating": false,
                    "floating_users": 0,
                    "is_trial": false,
                    "trial_days": 1,
                    "prevent_vm": false,
                    "metadata": {},
                    "is_hardware_key_auth": false,
                    "bundle_license_id": "1742897554024029",
                    "order_id": "1742897553827009",
                    "LicenseProductFeatures": [
                        {
                            "id": "1742897554115049",
                            "product_feature_id": 5,
                            "max_consumption": 12,
                            "expiry_date": null,
                            "metadata": {},
                            "is_floating": false,
                            "is_floating_cloud": false,
                            "floating_timeout": 120,
                            "floating_users": 1
                        }
                    ],
                    "LicenseCustomFields": []
                },
                {
                    "id": "1742897554118059",
                    "product_id": 1,
                    "active": false,
                    "enabled": true,
                    "created_at": 1742897554120,
                    "updated_at": 1742897554120,
                    "license_type": "perpetual",
                    "max_activations": 1,
                    "allow_unlimited_activations": false,
                    "valid_duration": null,
                    "floating_timeout": 120,
                    "max_transfers": 0,
                    "can_borrow": false,
                    "max_borrow_time": 0,
                    "start_date": null,
                    "is_air_gapped": false,
                    "license_template_id": null,
                    "validity_period": null,
                    "subscription_id": "",
                    "enable_maintenance_period": false,
                    "is_floating_cloud": false,
                    "is_floating": false,
                    "floating_users": 0,
                    "is_trial": false,
                    "trial_days": 1,
                    "prevent_vm": false,
                    "metadata": {},
                    "is_hardware_key_auth": false,
                    "bundle_license_id": "1742897554024029",
                    "order_id": "1742897553827009",
                    "LicenseProductFeatures": [
                        {
                            "id": "1742897554207069",
                            "product_feature_id": 5,
                            "max_consumption": 12,
                            "expiry_date": null,
                            "metadata": {},
                            "is_floating": false,
                            "is_floating_cloud": false,
                            "floating_timeout": 120,
                            "floating_users": 1
                        }
                    ],
                    "LicenseCustomFields": []
                }
            ]
        }
    ],
    "new_passwords": [
        []
    ]
}
```
:::

### Licenses

Each entry in the `items` array specifies a product code and a list of licenses being associated to that product. The following examples show a minimal order request payload for key-based and user-based licenses:

:::CodeblockTabs
Key-based license order

```json
{
    "id": "id_1546606209296",
    "items": [
        {
            "product_code": "TT",
            "licenses": [
                {
                    "key": "123-123-123-123-123"
                }
            ]
        }
    ]
}
```

User-based license order

```json
{
    "id": "id_1546606209296",
    "items": [
        {
            "product_code": "TT",
            "licenses": [
                {
                    "users": [{
                        "email": "end-user@gmail.com",
                        "is_manager": false
                    }]
                }
            ]
        }
    ]
}
```
:::

For each license you can specify a `policy_code` within the license object which will assign properties to a license based on the specified License Policy. (For more details on these properties, see the next section). If no policy code is specified, the default license policy defined for the Product will be used.

You can also explicitly specify license properties which will override the License Policy values. For example:

```json
{
    "id": "id_1546606209296",
    "items": [
        {
            "product_code": "TT",
            "licenses": [
                {
                    "key": "123-123-123-123-123",
                    "policy_code": "policy_A",
                    "max_activations": 10
                }
            ]
        }
    ]
}
```

In the above example, all License properties for the created license will be taken from the License Policy "policy\_A", with the exception of the `max_activations` property which was explicitly specified in the order request payload.

### Authorization methods: Key-based vs. User-based licenses

Each product you create in the system allows for one of two possible license authorization methods:

- **Key-based**: clients interacting with the license are required to provide a license key in their request
- **User-based**: clients interacting with the license are required to provide user credentials in their request

When sending an order creation request, the authorization method of licenses in the request are determined by each license's product.

- When creating key-based licenses in an order, you can provide a license key in the `key` property of the license. This is optional, and if omitted our system will generate a unique license key which will be returned to you in the order creation response object.
- When creating user-based licenses in an order, you must specify the users (1 or more) attached to that license by specifying them in a list in the `users` property of the license.

### Additional license properties

- `max_activations` - maximum number of time this license can be activated. If not set, product max activations is being used if defined for the product, if not - default value of 1 activation is being used.
- `license_type` - type of license - value can be either `time-limited`,  `perpetual` `consumption` or `subscription`. If it is a time limited license, `valid_duration` should also be set for the license. If it is perpetual license then valid duration does not apply and if consumption, `max_consumptions` is being used and should be set in order, if not, product max consumptions is being used.

:::hint{type="info"}
For **subscription licenses**, LicenseSpring requires an integration to an external source of truth (like a recurring billing system). LicenseSpring updates the status of the license according to the status of the subscription, which is handled by a 3rd party. Without this integration, subscription licenses remain valid until otherwise specified
:::

- `max_consumptions` - used in pair with consumption `license_type` - defines how many times product can be used within the license.
- `valid_duration` - defines how long license should be valid - value examples: `1y` (one year) or `2m` (2 months) or `3d `(3 days) or `4h` (4 hours) or `5min` (5 minutes).
- `enable_maintenance_duration` - whether license should consider maintenance duration, used in pair with `maintenance_duration`.
- `start_date` - start date of license `"2024-03-12"`
- `maintenance_duration` - duration of license maintenance period -  value examples: `1y` (one year) or `2m` (2 months) or `3d` (3 days).
- `validity_period` - final end date and time license is valid.
- `product_features` - array of additional product features
  - shorter version with product feature code only: `["feature1", "feature2"]`
  - longer version as an object with the `code` property and any additional property as an overrided value, eg: `[{ "code": "feature_code", "max_consumption": 33, "expiry_date": "2027-05-23" }]`. For a full definition of this object see **ProductFeature** in the Request definition above
- `is_trial` - boolean, defaults to False - whether this is a trial license or not.
- `prevent_vm` - boolean, defaults to False - whether license should be allowed on virtual machines.
- `max_transfers` - integer, defaults to 0 (Device transfer **not allowed**) - limit of license transfers between different devices.

For user-based licenses, instead of a license key, user is assigned as an object:

- `email` - required, email of the license user
- `is_manager` - optional (default false), if this user is license manager for all licenses in this order

Only for `consumption` licenses:

- `allow_overages` - boolean, defaults to False - whether license should allow overage license usage regardless the consumption, value example: `true` or `false`
- `max_overages` - number, maximum overage of consumption over the `max_consumption`.
- `reset_consumption` - boolean, defaults to False, whether license consumption my be reset, value example: `true` or `false`
- `consumption_period` - period over which licenses are reset - `week`, `month` or `year`

## Bundle Product Orders

LicenseSpring allows for products to be bundled, and the two types of products discussed in this article respective to bundling are:

- Non-bundle products (default) - these are singular products where each license is attached to one product. Clients interacting with these licenses use the following endpoints on the License API:
  - [**Activate License (Online Method)**](docId\:Mt2yGm6CJzh2bumU-Gfww)&#x20;
  - [**Activate License (Offline Method)**](docId\:H_VEWmE7rYJ7QfbIKvGuP)&#x20;
  - [**Check License**](docId\:Zh4KFIh_s59TzIBZKeb9o)&#x20;
  - [**Deactivate Bundle (Online Method)**](docId\:nzu6SRyNQLlEd2_-HhvhR)&#x20;
  - [**Deactivate License (Offline Method)**](docId\:iyg1DXIYqp9vW-Mlj-xUk)&#x20;
- Bundle products - these are products that contain multiple products within. The system creates a license for both the bundle itself and the products contained in the bundle. Activating/deactivating the top-level bundle license also activates/deactivates the licenses included within the bundle. Clients interacting with these licenses use the following endpoints on the License API:
  - [**Activate Bundle (Online Method)**](docId\:sj4ujBbDqwMf3QJDVNHdh)&#x20;
  - [**Activate Bundle (Offline Method)**](docId:0AWEA7jLUGzT14Z9_QSqi)&#x20;
  - [**Check Bundle**](docId\:odudSbU1BNxycgT4zx8FW)&#x20;
  - [**Deactivate Bundle (Online Method)**](docId\:nzu6SRyNQLlEd2_-HhvhR)&#x20;
  - [**Deactivate Bundle (Offline Method)**](docId\:UCxi3f0Ly0ysvOuQHH8lF)&#x20;

A Bundle Order contains multiple products linked to a single Bundle Product. To create a Bundle Order, you have to set the `is_bundle` property, and the products within the bundle are explicitly specified within each License object, as in the following examples:

:::CodeblockTabs
Bundle of key-based licenses

```json
{
    "id": "2cdf5739334b4688b04c4bbfb3da89618",
    "is_bundle": true,
    "append": false,
    "customer": null,
    "items": [
        {
            "product_code": "drama", // bundle product code
            "key": "GP14Q-QA4Z-M6SK-CXBU",
            "users": [],
            "licenses": [
                {
                    "policy_code": "dftlp", // the deprecated name for this attribute is "license_template_code"
                    "product_code": "p"
                },
                {
                    "policy_code": "dftlp",
                    "product_code": "p34"
                }
            ]
        }
    ],
    "reference": ""
}
```

Bundle of user-based licenses

```json
{
    "id": "2cdf57393364b4688b304c4bbfb9da89618",
    "is_bundle": true,
    "append": false,
    "customer": null,
    "items": [
        {
            "product_code": "d1", // bundle product code
            "users": [
                {
                    "email": "myuser@test.com",
                    "is_manager": false
                }
            ],
            "licenses": [
                {
                    "policy_code": "dftlp",
                    "product_code": "p2"
                },
                {
                    "policy_code": "dftlp",
                    "product_code": "12"
                }
            ]
        }
    ],
    "reference": ""
}
```
:::

:::hint{type="warning"}
For Bundle Orders, the `policy_code` property is mandatory
:::

:::hint{type="info"}
For Bundle Orders, the `policy_code` property has an alternate name: `license_template_code`. Both function identically, though the `license_template_code` name is considered deprecated on the API
:::


[title] Add manager to License User Group
[path] Management API/License/User Groups/

Adds a manager to a single License user group.

**URL** : `/api/v1/license-user-groups/{id}/add_manager/`

**Method** : `POST`

### Data example

```json
{
    "email": "example@gmail.com",
    "password": "Test1234!43210",
    "first_name": "First 1",
    "last_name": "Last 1"
}
```

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{
    "id": 3621,
    "true_email": "example@gmail.com",
    "is_initial_password": true,
    "initial_password": "Test1234!43210",
    "first_name": "First 1",
    "last_name": "Last 1",
    "phone_number": "",
    "new_user": true,
    "password": "Test1234!43210"
}
```


[title] Retrieve Installation File
[path] Management API/Product/Installation Files/

:::ApiMethodV2
```json
{
  "name": "Retrieve a single installation file if requesting manager has access permissions to it.",
  "method": "GET",
  "url": "/api/v1/installation-files/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "nlNbJDiSuocb6uxJIMQyS",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "nlNbJDiSuocb6uxJIMQyS"
  },
  "results": {
    "languages": [
      {
        "id": "K8pRz5K5-qClUBhYt5pcU",
        "language": "200",
        "code": "{\n    \"id\": 733286,\n    \"created_at\": \"2020-11-05T12:32:41Z\",\n    \"updated_at\": \"2020-11-05T12:32:41Z\",\n    \"version\": \"ver1.1\",\n    \"full_link\": \"http://www.africau.edu/images/default/sample.pdf\",\n    \"filename\": \"sample.pdf\",\n    \"release_date\": \"2020-11-04\",\n    \"enabled\": true,\n    \"hash_md5\": \"96962fd22cae41c54a3622ea79cd2bf8\",\n    \"environment\": \"linux\",\n    \"release_notes_link\": \"http://www.africau.edu/images/default/sample.pdf\",\n    \"eula_link\": \"http://www.africau.edu/images/default/sample.pdf\",\n    \"size\": \"123\",\n    \"requires_version\": \"ver1.5\",\n    \"product\": 1584723961091261\n}",
        "customLabel": ""
      },
      {
        "id": "8F_CRVQ_Qd4sG9phW1391",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "K8pRz5K5-qClUBhYt5pcU"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "retrieve-a-single-installation-file-if-requesting",
  "legacyHash": "3_fF5Syn-7MN_K5Y4zHes"
}
```
:::


[title] Delete License
[path] Management API/License/

Deletes a single license if requesting manager has access permissions to it.

**URL**: `/api/v1/licenses/{id}/`

**Method**: `DELETE`

### Success Response:

**Code**: `204 No Content`

[title] Reset License
[path] Management API/License/

Resets a single license, if requesting manager has access permissions to it.

**URL**: `/api/v1/licenses/{id}/reset/`

**Method**: `POST`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "message": "License and all devices reset."
}
```


[title] Retrieve Licenses Import Result
[path] Management API/License/Import Results/

Retrieves a single licenses import result, if requesting manager has access permissions to it.

**URL**: `/api/v1/licenses-import-results/{id}/`

**Method**: `GET`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 14,
    "file_name": "simple_licenses_example.csv",
    "status": "success",
    "created_at": "2021-04-22T11:14:21.345069Z",
    "started_at": "2021-04-22T11:14:24.461055Z",
    "finished_at": "2021-04-22T11:14:26.861156Z",
    "result": {
        "total_row_count": 2,
        "valid_row_count": 2,
        "invalid_rows": [],
        "created_customers_count": 0,
        "existed_customers_count": 2,
        "created_orders_count": 1,
        "existed_orders_count": 1,
        "created_licenses_count": 2,
        "existed_licenses_count": 0
    }
}
```


[title] Export License Users
[path] Management API/License/

Export the license users assigned to a license, if requesting manager has access permissions to them.

**URL**: `/api/v1/licenses/{id}/export_license_users/`

**Method**: `GET`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```csv
"id","email","first_name","last_name","phone_number","max_activations","total_activations","allow_unlimited_activations"
3442,"test1@licensespring.com","","","",1,3,True
3443,"test2@licensespring.com","","","",1,5,True
3466,"test3@licensespring.com","","","",1,2,True
3467,"test4@licensespring.com","","","",1,0,True
```


[title] Set Password for License User
[path] Management API/License/Users/

Sets password for a single license user, if requesting manager has access permissions to it.

**URL**: `/api/v1/license-users/{id}/set_password/`

**Method**: `POST`

### Data Example:

```json
{
    "password": "pass123"
}
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "message": "Password set."
}
```


[title] List License User Group members
[path] Management API/License/User Groups/

Show all license user group members.

**URL** : `/api/v1/license-user-groups/{id}/members/`

**Method** : `GET`

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
[
    {
        "id": 2986,
        "last_login": null,
        "email": "c@c.com|uss1",
        "true_email": "c@c.com",
        "created_at": "2024-06-25T07:15:05Z",
        "updated_at": "2024-06-25T07:15:06Z",
        "is_active": true,
        "first_name": "",
        "last_name": "",
        "phone_number": "",
        "subscribed_to_email": false,
        "acquired_consent": null,
        "initial_password": "m_266@iq",
        "is_initial_password": true
    }
]
```


[title] Retrieve License Features Import Result
[path] Management API/License/Features Import Results/

Retrieves a single license features import result, if requesting manager has access permissions to it.

**URL**: `/api/v1/license-features-import-results/{id}/`

**Method**: `GET`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 12,
    "file_name": "lpf_example.csv",
    "status": "success",
    "created_at": "2021-05-28T07:41:50.247644Z",
    "started_at": "2021-05-28T07:41:58.090021Z",
    "finished_at": "2021-05-28T07:42:03.189833Z",
    "result": {
        "total_row_count": 5,
        "valid_row_count": 5,
        "invalid_rows": [],
        "created_license_features": 5,
        "existed_license_features": 0
    }
}
```


[title] Delete License Product Feature
[path] Management API/License/ Features/

Deletes a single license product feature, if requesting manager has access permissions to it.

**URL**: `/api/v1/license-product-features/{id}`

**Method**: `DELETE`

### Success Response:

**Code**: `204 No Content`

[title] List License Usage Histories
[path] Management API/License/Usage Histories/

Show all license usage histories the requesting manager has access permissions to.

**URL**: `/api/v1/license-histories/`

**Method**: `GET`

### Query Parameters:

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on license activation history or related to the license activation history.

Possible filters:

- `license`
- `ts__gte`
- `ts__lte`
- `ts__date__gte`
- `ts__date__lte`
- `text`
- `product__in`
- `text__icontains`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "count": 3,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 74336,
            "device": null,
            "license_user": null,
            "ts": "2021-08-30T06:44:45Z",
            "source": "api",
            "sdk_version": null,
            "level": "info",
            "text": "License created",
            "data": null,
            "license": 1630305885777219
        },
        ...
    ]
}
```


[title] Retrieve License Custom Field
[path] Management API/License/Custom Fields/

Retrieves a single license custom field, if requesting manager has access permissions to it.

**URL**: `/api/v1/license-custom-fields/{id}/`

**Method**: `GET`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 78,
    "value": "23",
    "license": 1609234933166159,
    "product_custom_field": 51
}
```


[title] Disable License
[path] Management API/License/

Disables a single license, if requesting manager has access permissions to it.

**URL**: `/api/v1/licenses/{id}/disable/`

**Method**: `POST`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "message": "License disabled."
}
```


[title] Retrieve License User Group
[path] Management API/License/User Groups/

Retrieve a single license user group.

**URL** : `/api/v1/license-user-groups/{id}/`

**Method** : `GET`

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{
    "id": 9,
    "metadata_string": null,
    "customer_account": null,
    "created_at": "2025-06-24T10:52:58.156907Z",
    "updated_at": "2025-06-24T10:52:58.156952Z",
    "code": "lug5",
    "name": "lug5",
    "description": "",
    "metadata": {},
    "company": 277
}
```


[title] Remove Manager from Order
[path] Management API/Order/

:::ApiMethodV2
```json
{
  "name": "Removes a order manager from a single order if requesting manager has access permissions to it.",
  "method": "POST",
  "url": "/api/v1/orders/{id}/remove_manager/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "5-QCF02mmyXpoc8A8Aj0k",
        "language": "json",
        "code": "{\n    \"license_user_id\": 2149\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "5-QCF02mmyXpoc8A8Aj0k"
  },
  "results": {
    "languages": [
      {
        "id": "_Q5L_GyCniyvLghfl4GtI",
        "language": "200",
        "code": "{\n    \"detail\": \"removed\"\n}",
        "customLabel": ""
      },
      {
        "id": "CvrCgwGgzgOw7dNL6Iamh",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "_Q5L_GyCniyvLghfl4GtI"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "removes-a-order-manager-from-a-single-order-if-req",
  "legacyHash": "ZjRY2rkk3UDUXsnq3PMPg"
}
```
:::


[title] Reset Licenses (Bulk)
[path] Management API/License/

Reset multiple licenses, if requesting manager has access permissions to them.

**URL**:`/api/v1/licenses/reset_bulk/`

**Method**: `POST`

### Data Example:

```json
[
    1593781720493289,
    1593781746897319,
    1593781767723349
]
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "message": "Licenses and related devices reset."
}
```


[title] Retrieve License
[path] Management API/License/

Retrieves a single license, if requesting manager has access permissions to it.

**URL**: `/api/v1/licenses/{id}/`

**Method**: `GET`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 1593781720493289,
    "status": "Inactive",
    "floating_in_use_devices": 0,
    "customer": {
        "id": 620,
        "total_orders": 14,
        "total_licenses": 45,
        "labels": [
            {
                "id": 3,
                "label_id": 8,
                "label": "Customer",
                "color": "#ff9f43"
            },
            {
                "id": 53,
                "label_id": 34,
                "label": "Loyal",
                "color": "#3a0cd4"
            }
        ],
        "email": "tc@tc.com",
        "first_name": "",
        "last_name": "",
        "company_name": "",
        "phone": "",
        "reference": "",
        "address": "",
        "postcode": "",
        "city": "",
        "country": "",
        "state": "",
        "clabels_all": "customerloyal",
        "cognito_user_pool_id": "",
        "metadata": {},
        "company": 277,
        "license_user": null,
        "clabels": [
            8,
            34
        ]
    },
    "product_features": [
        {
            "id": 1596179495925542,
            "product_feature": {
                "id": 173,
                "created_at": "2020-09-14T11:17:43Z",
                "updated_at": "2020-09-14T11:17:43Z",
                "name": "Feature 3",
                "code": "f3",
                "is_deleted": false,
                "feature_type": "consumption",
                "max_consumption": 2,
                "allow_overages": false,
                "max_overages": 0,
                "reset_consumption": false,
                "consumption_period": null,
                "metadata": {}
            },
            "max_consumption": 30,
            "total_consumptions": 0,
            "expiry_date": null,
            "allow_overages": false,
            "max_overages": 99,
            "reset_consumption": false,
            "consumption_period": null,
            "metadata": {}
        }
    ],
    "product_custom_fields": [],
    "license_users": [
        {
            "id": 1240,
            "last_login": null,
            "email": "example@email.com|uss1",
            "true_email": "example@email.com",
            "created_at": "2020-08-12T08:52:32Z",
            "updated_at": "2020-08-12T09:01:24Z",
            "is_admin": {},
            "is_active": true,
            "is_staff": false,
            "first_name": "John",
            "last_name": "Doe",
            "phone_number": "00385913109161",
            "subscribed_to_email": false,
            "acquired_consent": null,
            "is_manager": false,
            "initial_password": "4q3dg7!_",
            "is_initial_password": true,
            "max_activations": 1,
            "total_activations": 5
        }
    ],
    "order_store_id": "d2d2dce02c844d4492c9d48758aa143a",
    "active_up_to_date_devices": 0,
    "total_active_devices": 0,
    "product": {
        "id": 1584723961091234,
        "product_name": "mch",
        "custom_fields": [
            {
                "id": 239,
                "name": "t1",
                "data_type": null,
                "default_value": "333",
                "description": null,
                "product": 1584723961091234
            }
        ]
    },
    "installation_file": null,
    "license_user_group": null,
    "created_at": "2020-07-03T13:08:40Z",
    "updated_at": "2020-10-15T13:40:26Z",
    "license_key": null,
    "active": false,
    "enabled": true,
    "time_activated": "2020-10-10T14:42:16Z",
    "time_disabled": "2020-08-14T07:26:27Z",
    "max_activations": 6,
    "times_activated": 0,
    "valid_duration": null,
    "validity_period": "2020-09-30",
    "license_type": "perpetual",
    "enable_maintenance_period": true,
    "maintenance_duration": "3m",
    "maintenance_period": "2021-01-10",
    "is_trial": true,
    "max_consumptions": 0,
    "total_consumptions": 0,
    "subscription_id": null,
    "last_check": null,
    "prevent_vm": true,
    "allow_overages": false,
    "max_overages": 0,
    "reset_consumption": false,
    "consumption_period": null,
    "trial_days": 0,
    "is_floating": false,
    "is_floating_cloud": true,
    "floating_users": 1,
    "note": null,
    "max_license_users": 0,
    "transfer_count": 0,
    "floating_timeout": null,
    "max_transfers": 0,
    "is_air_gapped": false,
    "can_borrow": false,
    "max_borrow_time": 0,
    "is_bundle": false,
    "metadata": {},
    "order": 1593781720493279,
    "order_item": 1593781720493299,
    "disabled_user": null,
    "last_activation_device": null
}
```


[title] List License User Groups for License User
[path] Management API/License/Users/

Show all license user groups for license user.

**URL** : `/api/v1/license-user-groups/{id}/members/`

**Method** : `GET`

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
[
    {
        "id": 2,
        "metadata_string": null,
        "created_at": "2025-03-19T09:13:54.995348Z",
        "updated_at": "2025-05-22T12:43:29.568017Z",
        "code": "lug1",
        "name": "License User Group 1",
        "description": "Some description.",
        "metadata": {
            "this": "that",
            "number": 1
        },
        "company": 277,
        "customer_account": 49
    }
]
```


[title] Delete License Custom Field
[path] Management API/License/Custom Fields/

Deletes a single license custom field, if requesting manager has access permissions to it.

**URL**: `/api/v1/license-custom-fields/{id}/`

**Method**: `DELETE`

### Success Response:

**Code**: `204 No Content`

[title] Delete License Policy
[path] Management API/License/License Policies/

Delete a single license policy if requesting manager has access permissions to it.

**URL** : `/api/v1/license-templates/{id}/`

**Method** : `DELETE`

### Success Response

**Code** : `204 No Content`

[title] Remove manager from License User Group
[path] Management API/License/User Groups/

Removes a manager from a single License User Group.

**URL** : `/api/v1/license-user-groups/{id}/remove_manager/`

**Method** : `POST`

### Data example

```json
{
    "license_user_id": 3420
}
```

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{
    "id": 3420,
    "true_email": "example@gmail.com",
    "is_initial_password": true,
    "initial_password": "test1234",
    "first_name": "First 1",
    "last_name": "Last 1",
    "phone_number": "",
    "new_user": false
}
```


[title] Retrieve License Usage History
[path] Management API/License/Usage Histories/

Retrieve a single license usage history if requesting manager has access permissions to it.

**URL**: `/api/v1/license-histories/{id}/`

**Method**: `GET`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 74336,
    "device": null,
    "license_user": null,
    "ts": "2021-08-30T06:44:45Z",
    "source": "api",
    "sdk_version": null,
    "level": "info",
    "text": "License created",
    "data": null,
    "license": 1630305885777219
}
```


[title] Update License user group
[path] Management API/License/User Groups/

Updates a license user group.

**URL** : `/api/v1/license-users/{id}/`

**Method** : `PATCH`

### Parameters

- `customer_account` - Integer
- `name` - String
- `description` - String
- `metadata` - JSON

### Data example

```json
{
    "description": "Harry"
}
```

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{
    "id": 9,
    "metadata_string": null,
    "customer_account": null,
    "created_at": "2025-06-24T10:52:58.156907Z",
    "updated_at": "2025-06-24T10:52:58.156952Z",
    "code": "lug5",
    "name": "lug5",
    "description": "Harry",
    "metadata": {},
    "company": 277
}
```


[title] List Licenses
[path] Management API/License/

Show all licenses the requesting manager has access permissions to.

**URL**: `/api/v1/licenses/`

**Method**: `GET`

### Query Parameters:

### Ordering:

- `order_by` - Which attribute to order the list by.
  - default ordering is ascending, can be made descending by prefixing the attribute name with `-`
  - Example: `order_by=created_at`
  - Example: `order_by=-created_at`

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

:::hint{type="info"}
The `/api/v1/licenses/`endpoint has a maximum pagination limit of  **100 items per request.** If a higher value is specified, the API does **not &#x20;**&#x72;eturn an error; instead, the response is automatically capped at 100 items.
:::

### Exact Filter

- `license_key`
- `active`
- `order__store_id`
- `order__customer_account`
- `order__customer_account__name`
- `order__customer_account__code`
- `customer_id`
- `customer_email`
- `customer__account`
- `customer__account__name`
- `customer__account__code`
- `customer__account__description`
- `customer__account__phone`
- `customer__account__address`
- `customer__account__email`
- `customer__account__reference`
- `product_id`
- `product_short_code`
- `product_features__id`
- `product__authorization_method`
- `license_users__id`
- `license_users__true_email`
- `devices__hostname`
- `devices__hardware_id`
- `devices__os`
- `subscription_id`
- `license_template_id`
- `license_template__code`
- `license_user_group`

### Icontains Filter

:::hint{type="info"}
Matches records where the string value is a **case-insensitive** substring of the field.&#x20;
:::

- `license_key__icontains`
- `order__store_id__icontains`
- `order__customer_account__name__icontains`
- `order__customer_account__code__icontains`
- `customer_email__icontains`
- `customer_company_name__icontains`
- `customer_name__icontains`
- `customer__reference__icontains`
- `customer__account__name__icontains`
- `customer__account__code__icontains`
- `customer__account__description__icontains`
- `customer__account__phone__icontains`
- `customer__account__address__icontains`
- `customer__account__email__icontains`
- `customer__account__reference__icontains`
- `product_name__icontains`
- `license_users__true_email__icontains`
- `devices__hostname__icontains`
- `devices__hardware_id__icontains`
- `devices__os__icontains`
- `license_template__code__icontains`
- `note__icontains`

### Startswith Filter

:::hint{type="info"}
Matches records where the string value is a starting **substring** of the field.&#x20;
:::

- `license_key__startswith`
- `order__store_id__startswith`

### In Filter

- `product_short_code__in`
- `customer_label__in`

### Date & Time Filters

- `__gt` — greater than
- `__gte` — greater than or equal
- `__lt` — less than
- `__lte` — less than or equal
- `__date__gt`, `__date__gte`,`__date__lt`, `__date__lte` — same comparisons but applied to the date portion only

These can be applied to following fields:

- `validity_period`
- `time_activated`
- `updated_at`
- `created_at`

### Boolean filters

- `enabled`
- `is_any_floating`
- `is_air_gapped`
- `is_bundle`
- `bundle_license__isnull`
- `is_trial`
- `has_max_consumptions`
- `is_hardware_key_auth`
- `active`
- `customer__account__isnull`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "count": 54,
    "next": "http://saas.licensespring.com/api/v1/licenses/?limit=20&offset=20",
    "previous": null,
    "results": [
        {
            "id": 1593781720493289,
            "status": "Inactive",
            "floating_in_use_devices": 0,
            "customer": {
                "id": 620,
                "total_orders": 14,
                "total_licenses": 45,
                "labels": [
                    {
                        "id": 3,
                        "label_id": 8,
                        "label": "Customer",
                        "color": "#ff9f43"
                    },
                    {
                        "id": 53,
                        "label_id": 34,
                        "label": "Loyal",
                        "color": "#3a0cd4"
                    }
                ],
                "email": "tc@tc.com",
                "first_name": "",
                "last_name": "",
                "company_name": "",
                "phone": "",
                "reference": "",
                "address": "",
                "postcode": "",
                "city": "",
                "country": "",
                "state": "",
                "clabels_all": "customerloyal",
                "cognito_user_pool_id": "",
                "metadata": {},
                "company": 277,
                "license_user": null,
                "clabels": [
                    8,
                    34
                ]
            },
            "product_features": [
                {
                    "id": 1596179495925542,
                    "product_feature": {
                        "id": 173,
                        "created_at": "2020-09-14T11:17:43Z",
                        "updated_at": "2020-09-14T11:17:43Z",
                        "name": "Feature 3",
                        "code": "f3",
                        "is_deleted": false,
                        "feature_type": "consumption",
                        "max_consumption": 2,
                        "allow_overages": false,
                        "max_overages": 0,
                        "reset_consumption": false,
                        "consumption_period": null,
                        "metadata": {}
                    },
                    "max_consumption": 30,
                    "total_consumptions": 0,
                    "expiry_date": null,
                    "allow_overages": false,
                    "max_overages": 99,
                    "reset_consumption": false,
                    "consumption_period": null,
                    "metadata": {},
                }
            ],
            "product_custom_fields": [],
            "license_users": [
                {
                    "id": 1240,
                    "last_login": null,
                    "email": "example@email.com|uss1",
                    "true_email": "example@email.com",
                    "created_at": "2020-08-12T08:52:32Z",
                    "updated_at": "2020-08-12T09:01:24Z",
                    "is_admin": {},
                    "is_active": true,
                    "is_staff": false,
                    "first_name": "John",
                    "last_name": "Doe",
                    "phone_number": "00385913109161",
                    "subscribed_to_email": false,
                    "acquired_consent": null,
                    "is_manager": false,
                    "initial_password": "4q3dg7!_",
                    "is_initial_password": true
                }
            ],
            "order_store_id": "d2d2dce02c844d4492c9d48758aa143a",
            "active_up_to_date_devices": 0,
            "total_active_devices": 0,
            "product": {
                "id": 1584723961091234,
                "product_name": "mch"
            },
            "created_at": "2020-07-03T13:08:40Z",
            "updated_at": "2020-10-15T13:40:26Z",
            "license_key": null,
            "active": false,
            "enabled": true,
            "time_activated": "2020-10-10T14:42:16Z",
            "time_disabled": "2020-08-14T07:26:27Z",
            "max_activations": 6,
            "times_activated": 0,
            "valid_duration": null,
            "validity_period": "2020-09-30",
            "license_type": "perpetual",
            "enable_maintenance_period": true,
            "maintenance_duration": "3m",
            "maintenance_period": "2021-01-10",
            "is_trial": true,
            "max_consumptions": 0,
            "total_consumptions": 0,
            "subscription_id": null,
            "last_check": null,
            "prevent_vm": true,
            "allow_overages": false,
            "max_overages": 0,
            "reset_consumption": false,
            "consumption_period": null,
            "trial_days": 0,
            "is_floating": false,
            "is_floating_cloud": true,
            "floating_users": 1,
            "note": null,
            "max_license_users": 0,
            "transfer_count": 0,
            "floating_timeout": null,
            "max_transfers": 0,
            "is_air_gapped": false,
            "can_borrow": false,
            "max_borrow_time": 0,
            "is_bundle": false,
            "metadata": {},
            "order": 1593781720493279,
            "order_item": 1593781720493299,
            "disabled_user": null,
            "last_activation_device": null
        },
        ...
    ]
}
```


[title] Enable License
[path] Management API/License/

Enables a single license, if requesting manager has access permissions to it.

**URL**: `/api/v1/licenses/{id}/enable/`

**Method**: `POST`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "message": "License enabled."
}
```


[title] Add Managers (bulk) to Order
[path] Management API/Order/

:::ApiMethodV2
```json
{
  "name": "Adds order managers (bulk) to a single Order if requesting manager has access permissions to it.",
  "method": "POST",
  "url": "/api/v1/orders/{id}/add_managers/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "PMdk2AQ7zOmitbAm_yJcY",
        "language": "json",
        "code": "[\n    {\n        \"email\": \"example1@gmail.com\",\n        \"password\": \"test1234!\",\n        \"first_name\": \"First 1\",\n        \"last_name\": \"Last 1\"\n        \"metadata\": {\n            \"this\": \"that\"\n        }\n    },\n    {\n        \"email\": \"example2@gmail.com\",\n        \"password\": \"test1234!\",\n        \"first_name\": \"First 1\",\n        \"last_name\": \"Last 1\"\n    }\n]",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "PMdk2AQ7zOmitbAm_yJcY"
  },
  "results": {
    "languages": [
      {
        "id": "r6WMFLtdwO76JZWkNsF9C",
        "language": "200",
        "code": "[\n    {\n        \"id\": 3433,\n        \"true_email\": \"example1@gmail.com\",\n        \"is_initial_password\": true,\n        \"initial_password\": \"test1234!\",\n        \"first_name\": \"First 1\",\n        \"last_name\": \"Last 1\",\n        \"phone_number\": \"\",\n        \"new_user\": true,\n        \"password\": \"test1234!\"\n        \"metadata\": {\n            \"this\": \"that\"\n        }\n    },\n    {\n        \"id\": 3434,\n        \"true_email\": \"example2@gmail.com\",\n        \"is_initial_password\": true,\n        \"initial_password\": \"test1234!\",\n        \"first_name\": \"First 1\",\n        \"last_name\": \"Last 1\",\n        \"phone_number\": \"\",\n        \"new_user\": true,\n        \"password\": \"test1234!\"\n        \"metadata\": {}\n    }\n]",
        "customLabel": ""
      },
      {
        "id": "0nQyaGQT6ZU41o-TlXjI2",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "r6WMFLtdwO76JZWkNsF9C"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "adds-order-managers-bulk-to-a-single-order-if-requ",
  "legacyHash": "xPs26nnNPWGULrwDku3ui"
}
```
:::


[title] Export Licenses History
[path] Management API/License/

Exports licenses history data to `csv` if requesting manager has access permissions to them.

:::hint{type="danger"}
This endpoint has been deprecated.
:::



**URL** : `/api/v1/licenses/export_history/`

**Method** : `GET`

### Success Response

**Code** : `200 OK`

**Content examples** :

```csv
ts,source,sdk_version,level,text,data,license_id,device_id,license_user_id
2022-03-28 08:15:56+00:00,api,,info,License created,,1648455355960029,,
2022-03-28 08:16:17+00:00,api,,info,License created,,1648455377530059,,
2022-04-12 06:50:16+00:00,api,,info,License check,,1641373808733019,1,
```


[title] Export Order
[path] Management API/Order/

:::ApiMethodV2
```json
{
  "name": "Export a single Order to CSV, if requesting manager has access permissions to them.",
  "method": "GET",
  "url": "/api/v1/orders/{id}/export/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "kg3f6B5R-_lNaBH-xll6O",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "kg3f6B5R-_lNaBH-xll6O"
  },
  "results": {
    "languages": [
      {
        "id": "iHUVicLdMsGm58RL3ibdN",
        "language": "200",
        "code": "\"order__id\",\"order__created_at\",\"order__reference\",\"order__store_id\",\"order__type\",\"customer__first_name\",\"customer__last_name\",\"customer__email\",\"customer__company_name\",\"customer__phone\",\"customer__reference\",\"customer__address\",\"customer__postcode\",\"customer__state\",\"customer__city\",\"customer__country\",\"license__id\",\"license__license_key\",\"license__created_at\",\"license__updated_at\",\"license__license_type\",\"license__time_activated\",\"license__max_activations\",\"license__allow_unlimited_activations\",\"license__times_activated\",\"license__active\",\"license__features\",\"license__prevent_vm\",\"license__valid_duration\",\"license__validity_period\",\"license__max_consumptions\",\"license__total_consumptions\",\"license__subscription_id\",\"license__last_check\",\"license__allow_overages\",\"license__max_overages\",\"license__reset_consumption\",\"license__consumption_period\",\"license__user_emails\",\"license__custom_fields\",\"license__start_date\",\"license__is_air_gapped\",\"license__is_trial\",\"license__is_floating\",\"license__is_floating_cloud\",\"license__floating_users\",\"license__enable_maintenance_period\",\"license__maintenance_duration\",\"license__maintenance_period\",\"license__note\",\"license__max_transfers\",\"license__floating_timeout\",\"license__enabled\",\"license__allow_unlimited_consumptions\",\"license__allow_negative_consumptions\",\"license__time_disabled\",\"license__trial_days\",\"license__max_license_users\",\"license__transfer_count\",\"license__can_borrow\",\"license__max_borrow_time\",\"license__is_bundle\",\"license__allow_grace_period\",\"license__grace_period\",\"license__is_hardware_key_auth\",\"product__name\",\"product__short_code\"\n1739461183126009,\"2025-02-13 15:39:43+00:00\",\"karlo_test_2\",\"karlo_test_2\",\"normal\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",1739461183210019,\"DCGN-QUU5-CQC4-HCFO\",\"2025-02-13 15:39:43+00:00\",\"2025-02-13 15:39:43+00:00\",\"perpetual\",\"\",1,False,0,False,\"\",False,\"\",\"\",\"\",0,\"\",\"\",False,0,False,\"\",\"\",\"\",\"\",False,False,False,False,1,False,\"\",\"\",\"\",0,120,True,False,True,\"\",1,1,0,False,0,False,False,0,False,\"Foo App\",\"fooapp\"",
        "customLabel": ""
      },
      {
        "id": "-62kF3_LG1zOUJKCVJb_L",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "iHUVicLdMsGm58RL3ibdN"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "export-a-single-order-to-csv-if-requesting-manager",
  "legacyHash": "CgU8SM9nT07UeZ2c_Hm4W"
}
```
:::


[title] List Managers on Order
[path] Management API/Order/

:::ApiMethodV2
```json
{
  "name": " Lists all order managers the requesting manager has access permissions to.",
  "method": "GET",
  "url": "/api/v1/orders/{id}/managers/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "9ZL1FTMahP5Q5b4yYBvKR",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "9ZL1FTMahP5Q5b4yYBvKR"
  },
  "results": {
    "languages": [
      {
        "id": "5ijac1hnY0mNmRnBT_yGy",
        "language": "200",
        "code": "[\n    {\n        \"id\": 1879,\n        \"true_email\": \"tc@tc.com\",\n        \"is_initial_password\": true,\n        \"initial_password\": \"HiYDpXoB\",\n        \"first_name\": \"\",\n        \"last_name\": \"\",\n        \"phone_number\": \"\"\n    },\n    ...\n]",
        "customLabel": ""
      },
      {
        "id": "I5SwZeD2JzX4b4msycgdy",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "5ijac1hnY0mNmRnBT_yGy"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "lists-all-order-managers-the-requesting-manager-ha",
  "legacyHash": "u54bXrs61DRiSoSVYJ3cu"
}
```
:::


[title] Generate License Key
[path] Management API/Order/

:::ApiMethodV2
```json
{
  "name": "Generates License keys if requesting manager has access permissions to it.",
  "method": "GET",
  "url": "/api/v1/orders/generate_license/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "CvP7Ne35ZWQbqiE141yhw",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "CvP7Ne35ZWQbqiE141yhw"
  },
  "results": {
    "languages": [
      {
        "id": "-irM8L1gbH98aR2OtLrhX",
        "language": "200",
        "code": "[\n    \"G8HA-SRRZ-A6WK-TJWB\"\n]",
        "customLabel": ""
      },
      {
        "id": "_nAnl-fG72j9jySBM7GuD",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "-irM8L1gbH98aR2OtLrhX"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "product ",
        "kind": "required",
        "type": "string",
        "description": "Short code of a product.\nExample: product=wbhk\n",
        "": "Short code of a product.\nExample: product=wbhk\n"
      },
      {
        "name": "quantity",
        "kind": "optional",
        "type": "integer",
        "description": "Number of keys to generate.\nExample: quantity=1",
        "": "integer"
      },
      {
        "name": "key_length",
        "kind": "optional",
        "type": "integer",
        "description": "Number of characters in each key\nMust be between 16 and 240\nDefault: 16\n",
        "": "Number of characters in each key\nMust be between 16 and 240\nDefault: 16\n"
      },
      {
        "name": "alphabet ",
        "kind": "optional",
        "type": "string",
        "description": "Possible characters for each key \nDefault: 23456789ABCDEFGHJKLMNPQRSTUVWXYZ",
        "": "Possible characters for each key \nDefault: 23456789ABCDEFGHJKLMNPQRSTUVWXYZ"
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "generates-license-keys-if-requesting-manager-has-a",
  "legacyHash": "JFg8JC4OQbl3f2ODhmfse"
}
```
:::


[title] Update License
[path] Management API/License/

&#x20;Updates a single license, if requesting manager has access permissions to it.

:::hint{type="info"}
- When updating `valid_duration` , `validity_period` and `trial_days` you should also send the `is_trial`field.&#x20;
- When `updating maintenance_duration` or `maintenance_period` you should send the `enable_maintenance_period` field
:::

:::hint{type="warning"}
`valid_duration` and `validity_period` can't be sent is same update license request.
:::



**URL**: `/api/v1/licenses/{id}/`

**Method**: `PATCH`

### Parameters:

- `max_activations` - Integer
- `max_consumptions` - Integer
- `allow_overages` - Boolean
- `max_overages` - Integer
- `reset_consumption` - Boolean
- `consumption_period` - String
  - Choices: `daily`, `weekly`, `monthly`, `annualy`
- `is_trial` - Boolean
- `trial_days` - Integer
- `enable_maintenance_period` - Boolean
- `maintenance_duration` - String
  - Choices examples: `35d` (35 days), `4m` (4 months), `2y` (2 years)
- `is_floating` - Boolean
- `is_floating_cloud` - Boolean
- `floating_users` - Integer
- `valid_duration` - String
  - Choices examples: `35d` (35 days), `4m` (4 months), `2y` (2 years)
- `validity_period` - Date
  - Format: `yyyy-mm-dd` (2020-09-30)
- `prevent_vm` - Boolean
- `note` - String
- `max_license_users` - Integer
  - Default: 0 (unlimited)
- `floating_timeout` - Integer
- `max_transfers` - Integer
  - Default: 0 (unlimited)
- `allow_unlimited_activation`-Boolean
- `order` - Integer
- `"metadata"`-JSON object
- `allow_grace_period` - Boolean
- `grace_period` - Integer
- &#x20;`installation_file` - Integer

### Data example

```json
{
    "max_activations": 5
}
```

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{
    "id": 1593781720493289,
    "status": "Inactive",
    "floating_in_use_devices": 0,
    "customer": {
        "id": 620,
        "total_orders": 14,
        "total_licenses": 45,
        "labels": [
            {
                "id": 3,
                "label_id": 8,
                "label": "Customer",
                "color": "#ff9f43"
            },
            {
                "id": 53,
                "label_id": 34,
                "label": "Loyal",
                "color": "#3a0cd4"
            }
        ],
        "email": "tc@tc.com",
        "first_name": "",
        "last_name": "",
        "company_name": "",
        "phone": "",
        "reference": "",
        "address": "",
        "postcode": "",
        "city": "",
        "country": "",
        "state": "",
        "cognito_user_pool_id": "",
        "metadata": {},
        "clabels_all": "customerloyal",
        "company": 277,
        "license_user": null,
        "clabels": [
            8,
            34
        ]
    },
    "product_features": [
        {
            "id": 1596179495925542,
            "product_feature": {
                "id": 173,
                "created_at": "2020-09-14T11:17:43Z",
                "updated_at": "2020-09-14T11:17:43Z",
                "name": "Feature 3",
                "code": "f3",
                "is_deleted": false,
                "feature_type": "consumption",
                "max_consumption": 2,
                "allow_overages": false,
                "max_overages": 0,
                "reset_consumption": false,
                "consumption_period": null
            },
            "max_consumption": 30,
            "total_consumptions": 0,
            "expiry_date": null,
            "allow_overages": false,
            "max_overages": 99,
            "reset_consumption": false,
            "consumption_period": null,
            "metadata": {}
        }
    ],
    "product_custom_fields": [],
    "license_users": [
        {
            "id": 1240,
            "last_login": null,
            "email": "example@email.com|uss1",
            "true_email": "example@email.com",
            "created_at": "2020-08-12T08:52:32Z",
            "updated_at": "2020-08-12T09:01:24Z",
            "is_admin": {},
            "is_active": true,
            "is_staff": false,
            "first_name": "John",
            "last_name": "Doe",
            "phone_number": "00385913109161",
            "subscribed_to_email": false,
            "acquired_consent": null,
            "is_manager": false,
            "initial_password": "4q3dg7!_",
            "is_initial_password": true
        }
    ],
    "order_store_id": "d2d2dce02c844d4492c9d48758aa143a",
    "active_up_to_date_devices": 0,
    "total_active_devices": 0,
    "product": {
        "id": 1584723961091234,
        "product_name": "mch"
    },
    "created_at": "2020-07-03T13:08:40Z",
    "updated_at": "2020-11-13T07:38:16.788576Z",
    "license_key": null,
    "active": false,
    "enabled": true,
    "time_activated": "2020-10-10T14:42:16Z",
    "time_disabled": "2020-08-14T07:26:27Z",
    "max_activations": 5,
    "times_activated": 0,
    "valid_duration": null,
    "validity_period": "2020-09-30",
    "license_type": "perpetual",
    "enable_maintenance_period": true,
    "maintenance_duration": "3m",
    "maintenance_period": "2021-01-10",
    "is_trial": true,
    "max_consumptions": 0,
    "total_consumptions": 0,
    "subscription_id": null,
    "last_check": null,
    "prevent_vm": true,
    "allow_overages": false,
    "max_overages": 0,
    "reset_consumption": false,
    "consumption_period": null,
    "trial_days": 0,
    "is_floating": false,
    "is_floating_cloud": true,
    "floating_users": 1,
    "note": null,
    "max_license_users": 0,
    "transfer_count": 0,
    "floating_timeout": null,
    "max_transfers": 0,
    "is_air_gapped": false,
    "can_borrow": false,
    "max_borrow_time": 0,
    "is_bundle": false,
    "metadata": {},
    "order": 1593781720493279,
    "order_item": 1593781720493299,
    "disabled_user": null,
    "last_activation_device": null
}
```


[title] List License User Groups
[path] Management API/License/User Groups/

Show all license user groups.

**URL** : `/api/v1/license-user-groups/`

**Method** : `GET`

### Query parameters

### Pagination

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering

The results can be filtered by various attributes on license activation history or related to the license activation history.

Possible filters:

- `customer_account`
- `customer_account__code`
- `customer_account__code__icontains`
- `customer_account__name`
- `customer_account__name__icontains`
- `any__license_managers__id`
- `license_managers__id`
- `customer_account__license_managers__id`

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{
    "count": 2,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 9,
            "metadata_string": null,
            "customer_account": null,
            "created_at": "2025-06-24T10:52:58.156907Z",
            "updated_at": "2025-06-24T10:52:58.156952Z",
            "code": "lug5",
            "name": "lug5",
            "description": "",
            "metadata": {},
            "company": 277
        },
        ...
    ]
}
```


[title] List License Policies
[path] Management API/License/License Policies/

Show all license policies the requesting manager has access permissions to.

**URL** : `/api/v1/license-templates/`

**Method** : `GET`

### Query parameters

### Pagination

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering

Possible filters:

- `product`
- `is_air_gapped`
- `is_archived`
- `is_default`
- `is_sku`
- `metadata`

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{
    "id": 938,
    "license_product_feature_templates": [
        {
            "id": 246,
            "product_feature": {
                "id": 194,
                "created_at": "2021-01-13T08:38:38Z",
                "updated_at": "2021-01-13T08:38:38Z",
                "name": "f1",
                "code": "f1",
                "is_deleted": false,
                "feature_type": "activation",
                "max_consumption": 0,
                "allow_unlimited_consumptions": false,
                "allow_overages": false,
                "max_overages": 0,
                "reset_consumption": false,
                "consumption_period": null,
                "is_floating": false,
                "is_floating_cloud": false,
                "floating_users": 1,
                "floating_timeout": null,
                "metadata": {},
                "product": 1584723961091260
            },
            "feature_type": "activation",
            "max_consumption": 100,
            "allow_unlimited_consumptions": false,
            "allow_overages": false,
            "max_overages": 0,
            "reset_consumption": false,
            "consumption_period": null,
            "is_floating": false,
            "is_floating_cloud": false,
            "floating_users": 1,
            "floating_timeout": null,
            "metadata": {},
            "license_template": 938
        }
    ],
    "license_custom_field_templates": [
        {
            "id": 66,
            "product_custom_field": {
                "id": 69,
                "name": "cf44",
                "data_type": null,
                "default_value": "31",
                "description": null,
                "product": 1584723961091260
            },
            "name": "cf44",
            "data_type": null,
            "default_value": "69",
            "description": "Some description",
            "license_template": 938
        }
    ],
    "created_at": "2024-04-09T07:22:34.340092Z",
    "updated_at": "2024-04-09T07:22:34.340195Z",
    "name": "Example name",
    "code": "example_code",
    "is_default": false,
    "default_license_type": "perpetual",
    "allow_trial": true,
    "trial_days": 15,
    "max_activations": 100,
    "allow_unlimited_activations": false,
    "max_license_users": 1,
    "is_floating": true,
    "is_floating_cloud": true,
    "floating_users": 1,
    "floating_timeout": 120,
    "enable_maintenance_period": false,
    "maintenance_duration": "1y",
    "prevent_vm": false,
    "valid_duration": "1y",
    "allow_grace_period": false,
    "grace_period": 0,
    "max_consumptions": 1,
    "allow_unlimited_consumptions": false,
    "allow_overages": false,
    "max_overages": 0,
    "reset_consumption": false,
    "consumption_period": null,
    "max_transfers": 0,
    "is_air_gapped": false,
    "can_borrow": false,
    "max_borrow_time": 0,
    "is_archived": false,
    "is_hardware_key_auth": false,
    "validity_period": "2020-09-30",
    "metadata": {},
    "product": 1584723961091260,
    "installation_file": null,
    "is_sku": false,
    "user_max_activations": 3
}
```


[title] Floating Features
[path] Management API/License/


[title] Create License User Group
[path] Management API/License/User Groups/

Creates a license user group.

**URL** : `/api/v1/license-user-groups/`

**Method** : `POST`

### Parameters

- `code` - String
- `customer_account` - Integer
- `name` - String
- `description` - String
- `metadata` - JSON

### Data example

```json
{
    "code": "lug10",
    "name": "License User Group 10",
    "description": "Some description.",
}
```

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{
    "id": 12,
    "metadata_string": null,
    "created_at": "2025-07-02T11:04:55.666963Z",
    "updated_at": "2025-07-02T11:04:55.667010Z",
    "code": "lug10",
    "name": "License User Group 10",
    "description": "Some description.",
    "metadata": {},
    "company": 277,
    "customer_account": null
}
```


[title] Update Installation File
[path] Management API/Product/Installation Files/

Update a single installation file if requesting manager has access permissions to it.

**URL**: `/api/v1/installation-files/{id}/`

**Method**: `PATCH`

### Parameters:

- `environment` - String
  - Choices: `win`, `win32`, `win64`, `mac`, `linux`, `linux32`, `linux64`
- `hash_md5` - String
- `full_link` - String
- `product` - Integer
- `release_date` - Date
  - Format: `yyyy-mm-dd` (2020-09-30)
- `version` - String
- `release_notes_link` - String
- `eula_link` - String
- `size` - String
  - Digits only
- `requires_version` - String
  - Will be set to oldest existing version if not specified

### Data Example:

:::hint{type="info"}
When sending `full_link` field it will overwrite `filename` field
:::



```json
{
    "version": "7",
    "full_link": "full_link",
    "filename": "name",
    "release_date": "2023-11-09",
    "enabled": true,
    "hash_md5": "hhhdhfsdi",
    "environment": "linux",
    "release_notes_link": "link",
    "eula_link": "link",
    "size": 12,
    "requires_version": "7.222",
    "channel": "channel"
}
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 214,
    "created_at": "2023-11-22T11:11:07Z",
    "updated_at": "2024-10-10T09:30:07.360687Z",
    "version": "7",
    "full_link": "full_link",
    "filename": "full_link",
    "release_date": "2023-11-09",
    "enabled": true,
    "hash_md5": "hhhdhfsdi",
    "environment": "linux",
    "release_notes_link": "link",
    "eula_link": "link",
    "size": "12",
    "requires_version": "7.222",
    "channel": "channel",
    "product": 1683881296184003
}
```


[title] Retrieve License User
[path] Management API/License/Users/

mRetrieves a single license user, if requesting manager has access permissions to it.

**URL**: `/api/v1/license-users/{id}/`

**Method**: `GET`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 2270,
    "last_login": null,
    "email": "end-user@gmail.com|tn",
    "true_email": "end-user@gmail.com",
    "created_at": "2021-08-24T07:22:27Z",
    "updated_at": "2021-10-14T07:47:48Z",
    "is_active": true,
    "is_manager": false,
    "initial_password": "5dH7Oqfq",
    "is_initial_password": true,
    "first_name": "",
    "last_name": "",
    "phone_number": "",
    "total_licenses": 1,
    "customer_accounts": []
}
```


[title] Delete Installation File
[path] Management API/Product/Installation Files/

:::ApiMethodV2
```json
{
  "name": "Delete a single installation file, if requesting manager has access permissions to it.",
  "method": "DELETE",
  "url": "/api/v1/installation-files /{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "27Zq3pYphhanQJpnriHI-",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "27Zq3pYphhanQJpnriHI-"
  },
  "results": {
    "languages": [
      {
        "id": "GqObIhuGZ5zkcu26fW06k",
        "language": "204",
        "code": "Code: 204 No Content",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "GqObIhuGZ5zkcu26fW06k"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "delete-a-single-installation-file-if-requesting-ma",
  "legacyHash": "6widqk-pbNjXBMJfLBLhJ"
}
```
:::


[title] Export license histories
[path] Management API/License/Usage Histories/

Export all license histories the requesting manager has access permissions to.

**URL** : `/api/v1/license-histories/export`

**Method** : `GET`

### Query parameters

### Filtering

The results can be filtered by various attributes on customer account or related to the customer account.

Possible filters:

- `license`
- `ts__gte`
  - required (`ts__gte` and `ts__lte` filters must be within 24 hours)
- `ts__lte`
  - required (`ts__gte` and `ts__lte` filters must be within 24 hours)

### Success Response

**Code** : `200 OK`

**Content examples** :

```csv
"ts","source","sdk_version","level","text","data","license_id","device_id","license_user_id"
"2025-03-03 11:36:51+00:00","api","","info","License created","",1741001811379069,"",""
"2025-03-03 11:36:51+00:00","api","","info","License created","",1741001811383079,"",""
"2025-03-03 11:57:53+00:00","api","","info","License check","{""license_key"":""GYVH-BP62-AW2K-36LK"",""hardware_id"":""85545390726018""}",1684834244249059,1684834602354759,""
```


[title] Update Order
[path] Management API/Order/

:::ApiMethodV2
```json
{
  "name": "Update a single order if requesting manager has access permissions to it.",
  "method": "PATCH",
  "url": "/api/v1/orders/{id}/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "kNE5EPMHDvNYktBYpY0Fx",
        "language": "json",
        "code": "{\n    \"store_id\": \"patched_store_id\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "kNE5EPMHDvNYktBYpY0Fx"
  },
  "results": {
    "languages": [
      {
        "id": "L3I0xfND4jAIzlUpHrrdG",
        "language": "200",
        "code": "{\n    \"id\": 1629789747117569,\n    \"created_at\": \"2021-08-24T07:22:27Z\",\n    \"updated_at\": \"2021-11-23T07:04:07.441338Z\",\n    \"store_id\": \"patched_store_id\",\n    \"type\": \"normal\",\n    \"customer_email\": null,\n    \"is_test\": false,\n    \"customer_reference\": \"\",\n    \"is_trial\": false,\n    \"download_id\": null,\n    \"language\": null,\n    \"campaign_params\": null,\n    \"customer_first_name\": null,\n    \"customer_last_name\": null,\n    \"customer_company\": null,\n    \"customer_phone\": null,\n    \"metadata\": {},\n    \"company\": 339,\n    \"customer\": null,\n    \"customer_account\": null,\n    \"license_users\": []\n}",
        "customLabel": ""
      },
      {
        "id": "bmwOsQkFA730lMnsHCfAs",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "L3I0xfND4jAIzlUpHrrdG"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "store_id ",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "optional"
      },
      {
        "name": "type ",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "type "
      },
      {
        "name": "is_test ",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "is_trial ",
        "kind": "optional",
        "type": "boolean",
        "description": "",
        "": "boolean"
      },
      {
        "name": "download_id ",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "download_id "
      },
      {
        "name": "language ",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "language "
      },
      {
        "name": "campaign_params ",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "campaign_params "
      },
      {
        "name": "customer ",
        "kind": "optional",
        "type": "integer",
        "description": "",
        "": "integer"
      },
      {
        "name": "customer_account ",
        "kind": "optional",
        "type": "string",
        "description": "",
        "": "customer_account "
      },
      {
        "name": "metadata",
        "kind": "optional",
        "type": "object",
        "description": "\"metadata\"-JSON object",
        "": "\"metadata\"-JSON object"
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "update-a-single-order-if-requesting-manager-has-ac",
  "legacyHash": "AZAemjMJwHl_RUVqqIZru"
}
```
:::

###


[title] List License Product Features
[path] Management API/License/ Features/

Show all license product features the requesting manager has access permissions to.

**URL**: `/api/v1/license-product-features/`

**Method**: `GET`

### Query Parameters:

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

Possible filters:

- `license`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "count": 3,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 1698661568105404,
            "product_feature": {
                "id": 560,
                "created_at": "2023-10-30T10:18:51Z",
                "updated_at": "2023-10-30T10:22:09Z",
                "name": "f1",
                "code": "f1",
                "is_deleted": false,
                "feature_type": "consumption",
                "max_consumption": 7,
                "allow_unlimited_consumptions": false,
                "allow_overages": false,
                "max_overages": 0,
                "reset_consumption": false,
                "consumption_period": null,
                "is_floating": true,
                "is_floating_cloud": false,
                "floating_users": 13,
                "floating_timeout": 113,
                "metadata": {}
            },
            "device_features": [],
            "max_consumption": 10,
            "total_consumptions": 0,
            "allow_unlimited_consumptions": false,
            "expiry_date": null,
            "allow_overages": false,
            "max_overages": 0,
            "reset_consumption": false,
            "consumption_period": "monthly",
            "is_floating": true,
            "is_floating_cloud": false,
            "floating_users": 10,
            "floating_timeout": 120,
            "metadata": {},
            "license": 1698659715613589
        },
        ...
    ]
}
```


[title] /license-custom-fields/
[path] Management API/License/


[title] Reset Consumptions on License
[path] Management API/License/

Resets consumption on a single license, if requesting manager has access permissions to it.

**URL** : `/api/v1/licenses/{id}/reset_consumption`

**Method**: `POST`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "message": "License consumption reset."
}
```


[title] Add License User to License User Group
[path] Management API/License/Users/

Adds a license user to a license user group.

**URL** : `/api/v1/license-users/{id}/add_to_group/`

**Method** : `POST`

### Data example

```json
{
    "license_user_group_id": 2
}
```

### Success Response

**Code** : `200 OK`

[title] /license-import-results/
[path] Management API/License/

# List Licenses import results

Show all licenses import results the requesting manager has access permissions to.

**URL** : `/api/v1/licenses-import-results/`

**Method** : `GET`

### Query parameters

### Pagination

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering

The results can be filtered by various attributes on customer or related to the customer.

Possible filters:

- `status__iexact`
  - Choices: `pending`, `running`, `error`, `success`

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{
    "count": 9,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 14,
            "file_name": "simple_licenses_example.csv",
            "status": "success",
            "created_at": "2021-04-22T11:14:21.345069Z",
            "started_at": "2021-04-22T11:14:24.461055Z",
            "finished_at": "2021-04-22T11:14:26.861156Z",
            "result": {
                "total_row_count": 2,
                "valid_row_count": 2,
                "invalid_rows": [],
                "created_customers_count": 0,
                "existed_customers_count": 2,
                "created_orders_count": 1,
                "existed_orders_count": 1,
                "created_licenses_count": 2,
                "existed_licenses_count": 0
            }
        },
        ...
    ]
}
```


[title] License Templates
[path] Management API/License/


[title] Order
[path] Management API/


[title] Create License Policy
[path] Management API/License/License Policies/

Creates a license policy if requesting manager has access permissions to it.

**URL** : `/api/v1/license-templates/`

**Method** : `POST`

### Parameters

- `name` - String
- `code` - Integer
- `default_license_type` - String
- `allow_trial` - Boolean
- `trial_days` - Integer
- `max_activations` - Integer
- `allow_unlimited_activations` - Boolean
- `max_license_users` - Integer
- `is_floating` - Boolean
- `is_floating_cloud` - Boolean
- `floating_users` - Integer
- `floating_timeout` - Integer
- `enable_maintenance_period` - Boolean
- `maintenance_duration` - String
- `prevent_vm` - Boolean
- `valid_duration` - String
- `allow_grace_period` - Boolean
- `grace_period` - Integer
- `max_consumptions` - Integer
- `allow_unlimited_consumptions` - Boolean
- `allow_overages` - Boolean
- `max_overages` - Integer
- `reset_consumption` - Boolean
- `consumption_period` - Integer
- `max_transfers` - Integer
- `is_air_gapped` - Boolean
- `can_borrow` - Boolean
- `max_borrow_time` - Integer
- `is_archived` - Boolean
- `is_hardware_key_auth` - Boolean
- `metadata` - JSON
- `product` - Integer
- `installation_file` - Integer
- `is_sku` - Boolean
- `user_max_activations` - Integer
- `license_product_feature_templates` - list of objects:
  - `id` - Integer (id of product feature)
  - `max_consumption` - Integer
  - `allow_unlimited_consumptions` - Boolean
  - `allow_overages` - Boolean
  - `max_overages` - Integer
  - `reset_consumption` - Boolean
  - `consumption_period` - String
  - `is_floating` - Boolean
  - `is_floating_cloud` - Boolean
  - `floating_users` - Integer
  - `floating_timeout` - Integer
  - `metadata` - JSON
- `license_custom_field_templates` - list of objects:
  - `id` - Integer (id of product custom field)
  - `name` - String
  - `data_type` - String
  - `default_value` - String
  - `description` - String

### Data example

```json
{
    "name": "Example name",
    "code": "example_code",
    "product": 1584723961091260,
    "max_activations": 100,
    "is_floating": true,
    "is_floating_cloud": true,
    "license_product_feature_templates": [
        {
            "id": 200
        },
        {
            "id": 194,
            "max_consumption": 100
        }
    ],
    "license_custom_field_templates": [
        {
            "id": 200
        },
        {
            "id": 69,
            "default_value": 69,
            "description": "Some description"
        }
    ]
}
```

### Success Response

**Code** : `201 OK`

**Content examples** :

```json
{
    "id": 938,
    "license_product_feature_templates": [
        {
            "id": 246,
            "product_feature": {
                "id": 194,
                "created_at": "2021-01-13T08:38:38Z",
                "updated_at": "2021-01-13T08:38:38Z",
                "name": "f1",
                "code": "f1",
                "is_deleted": false,
                "feature_type": "activation",
                "max_consumption": 0,
                "allow_unlimited_consumptions": false,
                "allow_overages": false,
                "max_overages": 0,
                "reset_consumption": false,
                "consumption_period": null,
                "is_floating": false,
                "is_floating_cloud": false,
                "floating_users": 1,
                "floating_timeout": null,
                "metadata": {},
                "product": 1584723961091260
            },
            "feature_type": "activation",
            "max_consumption": 100,
            "allow_unlimited_consumptions": false,
            "allow_overages": false,
            "max_overages": 0,
            "reset_consumption": false,
            "consumption_period": null,
            "is_floating": false,
            "is_floating_cloud": false,
            "floating_users": 1,
            "floating_timeout": null,
            "metadata": {},
            "license_template": 938
        }
    ],
    "license_custom_field_templates": [
        {
            "id": 66,
            "product_custom_field": {
                "id": 69,
                "name": "cf44",
                "data_type": null,
                "default_value": "31",
                "description": null,
                "product": 1584723961091260
            },
            "name": "cf44",
            "data_type": null,
            "default_value": "69",
            "description": "Some description",
            "license_template": 938
        }
    ],
    "created_at": "2024-04-09T07:22:34.340092Z",
    "updated_at": "2024-04-09T07:22:34.340195Z",
    "name": "Example name",
    "code": "example_code",
    "is_default": false,
    "default_license_type": "perpetual",
    "allow_trial": true,
    "trial_days": 15,
    "max_activations": 100,
    "allow_unlimited_activations": false,
    "max_license_users": 1,
    "is_floating": true,
    "is_floating_cloud": true,
    "floating_users": 1,
    "floating_timeout": 120,
    "enable_maintenance_period": false,
    "maintenance_duration": "1y",
    "prevent_vm": false,
    "valid_duration": "1y",
    "allow_grace_period": false,
    "grace_period": 0,
    "max_consumptions": 1,
    "allow_unlimited_consumptions": false,
    "allow_overages": false,
    "max_overages": 0,
    "reset_consumption": false,
    "consumption_period": null,
    "max_transfers": 0,
    "is_air_gapped": false,
    "can_borrow": false,
    "max_borrow_time": 0,
    "is_archived": false,
    "is_hardware_key_auth": false,
    "metadata": {},
    "product": 1584723961091260,
    "installation_file": null,
    "is_sku": false
}
```


[title] Update License Product Feature
[path] Management API/License/ Features/

Updates a license product feature, if requesting manager has access permissions to it.

**URL**: `/api/v1/license-product-features/{id}`

**Method**: `PATCH`

### Parameters:

- `max_consumption` - Integer
- `allow_overages` - Boolean
- `consumption_period`
  - Choices: `daily`, `weekly`, `monthly`,`annualy `
- `reset_consumption` - Boolean
- `allow_unlimited_consumptions` - Boolean
- `metadata` - JSON
- `expiry_date` - Date
  - Fromat: `yyyy-mm-dd` (2020-09-30)
- `allow_unlimited_consumptions` - Bolean
- `floating_timeout` - Integer
- `is_floating` - Boolean
- `is_floating_cloud` - Boolean
- `floating_users` - Integer
- `allow_negative_consumptions` - Boolean

### Data Example:&#x20;

```json
{
"max_consumption":20,
"expiry_date":"2029-12-12",
"allow_overages":false,
"consumption_period":"daily",
"max_overages":10,
"reset_consumption":true,
"allow_unlimited_consumptions":false,
"metadata":{"b":"a"},
"floating_timeout":160,
"is_floating":false,
"is_floating_cloud":true,
"allow_negative_consumptions":true
}
```

### Success Response:

**Code** : `200 OK`

**Content examples** :

```json
{
    "id": 1728371110140213,
    "max_consumption": 20,
    "total_consumptions": 0,
    "allow_unlimited_consumptions": false,
    "allow_negative_consumptions": true,
    "expiry_date": "2029-12-12",
    "allow_overages": false,
    "max_overages": 10,
    "reset_consumption": true,
    "consumption_period": "daily",
    "is_floating": false,
    "is_floating_cloud": true,
    "floating_users": 1,
    "floating_timeout": 160,
    "metadata": {
        "b": "a"
    },
    "license": 1724914678024439,
    "product_feature": 170
}
```


[title] /license-users/
[path] Management API/License/


[title] /license-histories/
[path] Management API/License/


[title] List Installation Files
[path] Management API/Product/Installation Files/

:::ApiMethodV2
```json
{
  "name": "Show all installation files the requesting manager has access permissions to.",
  "method": "GET",
  "url": "/api/v1/installation-files/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "tQId7IrswOr8o16XEHPWE",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "tQId7IrswOr8o16XEHPWE"
  },
  "results": {
    "languages": [
      {
        "id": "2X5MslZsCDTtlvfVjoqF9",
        "language": "200",
        "code": "{\n    \"count\": 3,\n    \"next\": null,\n    \"previous\": null,\n    \"results\": [\n        {\n            \"id\": 733291,\n            \"created_at\": \"2020-11-05T12:52:17Z\",\n            \"updated_at\": \"2020-11-05T12:52:17Z\",\n            \"version\": \"ver1.5\",\n            \"full_link\": \"http://www.africau.edu/images/default/sample.pdf\",\n            \"filename\": \"sample.pdf\",\n            \"release_date\": \"2020-11-04\",\n            \"enabled\": true,\n            \"hash_md5\": \"96962fd22cae41c54a3622ea79cd2bf8\",\n            \"environment\": \"linux\",\n            \"release_notes_link\": \"http://www.africau.edu/images/default/sample.pdf\",\n            \"eula_link\": \"http://www.africau.edu/images/default/sample.pdf\",\n            \"size\": \"123\",\n            \"requires_version\": \"ver1.5\",\n            \"product\": 1584723961091256\n        },\n        ...\n    ]\n}",
        "customLabel": ""
      },
      {
        "id": "AuSE8SvC-r11qeYoPHtYt",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "2X5MslZsCDTtlvfVjoqF9"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "show-all-installation-files-the-requesting-manager",
  "legacyHash": "qpnlBZIxyWl8Cj0SIrIfm"
}
```
:::

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on installation file or related to the installation file.

Possible filters:

- `product`


[title] Disable Licenses (Bulk)
[path] Management API/License/

Disables multiple licenses, if requesting manager has access permissions to them.

**URL**: `/api/v1/licenses/disable_bulk/`

**Method**: `POST`

### Data Example:

```json
[
    1593781720493289,
    1593781746897319,
    1593781767723349
]
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "message": "Licenses disabled."
}
```


[title] Import Licenses From CSV
[path] Management API/License/

Imports licenses from CSV, if requesting manager has access permissions to it.

:::hint{type="warning"}
Ensure that all text fields in your CSV use **ASCII characters**. Non-ASCII characters (such as “ä”, “ñ”, or other special symbols) can cause import errors. To avoid issues, remove or replace these characters before uploading your file.
:::

**URL** : `/api/v1/licenses/import_from_csv/`

**Method** : `POST`

### Content-Type

Required `Content-Type` is `multipart/form-data` with the following single key value pair:

- Key: `file`
- Value: `{csv file from which to import}`

### Required CSV Headers

- `license__license_key`
- `product__short_code`

### Possible CSV Headers

- `customer__last_name`- last name of the customer
- `customer__company_name`- name of the company the customer is associated with
- `customer__phone`- phone number of the customer
- `customer__reference`- unique identifier or reference number for the customer
- `customer__address`- address of the customer
- `customer__postcode`- postal code associated with the customer's address
- `customer__state`- state or region of the customer's address
- `customer__city`- city of the customer's address
- `customer__country`- country of the customer's address
- `order__store_id`- unique identifier for the store from which the order was made
- `order__type`- type of order
- `order__is_test`- boolean flag indicating whether the order is a test order
- `order__is_trial`- boolean flag indicating whether the order is for a trial product
- `order__download_id`- unique identifier for any digital products that may need to be downloaded as part of the order
- `order__language`- language preference for the order
- `order__campaign_params`- parameters related to any marketing campaign associated with the order
- `license__license_key`- unique license key&#x20;
- `license__enabled`- boolean flag indicating whether the license is active and valid
- `license__max_activations`- maximum number of activations permitted for the license
- `license__allow_unlimited_activations `- permits unlimited activations for the license
- `license__validity_period`- period during which the license is valid
- `license__valid_duration`- the exact duration the license is valid for&#x20;

- `license__license_type`- the type of license(perpetual, time-limited, subscription, consumption)
- `license__enable_maintenance_period`- boolean flag indicating whether a maintenance period is enabled for the license
- `license__maintenance_period`- the duration of the maintenance period for the license
  - used to set the date when maintenance will end for this license, `license__enable_maintenance_period` must also be set for it to take effect
  - format: `YYYY-MM-DD`
  - example: `2023-09-15`
- `license__maintenance_duration`- the duration of the maintenance period for the license
- `license__is_trial`- boolean flag indicating whether the license is a trial license
- `license__max_consumptions`- maximum number of uses allowed
- `license__subscription_id`- identifier for any subscription plan associated with the license
- `license__prevent_vm`- boolean flag indicating whether the license prevents use in virtual machines
- `license__allow_overages`- boolean flag indicating whether overages are allowed
- `license__max_overages`- maximum allowable overages for the license
- `license__reset_consumption`- boolean flag indicating whether the consumption count for the license resets after a certain period
- `license__consumption_period`- period after which the consumption count resets
- `license__trial_days`- number of days for which the trial license is valid
- `license__is_floating`- boolean flag indicating whether the license is a floating license
- `license__is_floating_cloud`- boolean flag indicating whether the license is a cloud-based floating license
- `license__floating_users`- maximum number of concurrent users allowed under a floating license
- `license__note`- additional notes or information about the license
- `license__max_license_users`- maximum number of users who can use a single license
- `license__floating_timeout`- period of inactivity after which a floating license is released for use by another user
- `product__short_code`- short identifier or code for the product associated with the license

### Data example

```csv
customer__email,order__store_id,license__license_key,product__short_code
example1@email.com,pn7XXkuCRdsadasdy9S2XSsCYQ,impo-rtor-derk-ey00,psc
example1@email.com,pn7XXkuCRdsadasdy9S2XSsCYQ,impo-rtor-derk-ey01,psc
```

### Success Response

**Code** : `200 OK`

**Content examples** :

```json
{
    "job_id": 10
}
```

`job_id` from response can be used to query the import result.


[title] Delete Order
[path] Management API/Order/

:::ApiMethodV2
```json
{
  "name": "Delete a single order, if requesting manager has access permissions to it and the order does not have any licenses related to it.",
  "method": "DELETE",
  "url": "/api/v1/orders/{id}/safe_delete/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "nVYSn4HJtMIb3Y5eO29GF",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "nVYSn4HJtMIb3Y5eO29GF"
  },
  "results": {
    "languages": [
      {
        "id": "0W4KOutewwdUzj3hLV49u",
        "language": "204",
        "code": "Code: 204 ",
        "customLabel": ""
      },
      {
        "id": "rZtdMEDX98H9-UJ3slBVC",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "0W4KOutewwdUzj3hLV49u"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "delete-a-single-order-if-requesting-manager-has-ac",
  "legacyHash": "nNy6a3ITo4Hhph0a4G5QK"
}
```
:::

:::hint{type="danger"}
This endpoint deletes an existing order and cascades the deletion to all licenses and related data tied to the order.
**URL**:  /api/v1/orders/\{id}

**Method**: `DELETE`
:::


[title] Update Licenses (Bulk)
[path] Management API/License/

Updates multiple licenses if requesting manager has access permissions to it.

:::hint{type="info"}
When updating `valid_duration` , `validity_period` and `trial_days` you should also send `is_trial`field.&#x20;
:::

:::hint{type="warning"}
`valid_duration` and `validity_period` can't be sent is same update license request.
:::

**URL**: `/api/v1/licenses/bulk_update/`

**Method**: `PATCH`

### Parameters for Each License:

- `id` - Integer
  - Required
  - Must be provided in order to specify which fields will be updated on which License
- `max_activations` - Integer
- `max_consumptions` - Integer
- `allow_overages` - Boolean
- `max_overages` - Integer
- `reset_consumption` - Boolean
- `consumption_period` - String
  - Choices: `daily`, `weekly`, `monthly`, `annualy`
- `is_trial` - Boolean
- `trial_days` - Integer
- `enable_maintenance_period` - Boolean
- `maintenance_duration` - String
  - Choices examples: `35d` (35 days), `4m` (4 months), `2y` (2 years)
- `is_floating` - Boolean
- `is_floating_cloud` - Boolean
- `floating_users` - Integer
- `valid_duration` - String
  - Choices examples: `35d` (35 days), `4m` (4 months), `2y` (2 years)
- `validity_period` - Date
  - Format: `yyyy-mm-dd` (2020-09-30)
- `prevent_vm` - Boolean- `note` - String
- `max_license_users` - Integer
  - Default: 0 (unlimited)
- `floating_timeout` - Integer
- `max_transfers` - Integer
  - Default: 0 (unlimited)
- `"metadata"`-JSON object

### Data Example:

```json
[
    {
        "id": 1604392188374249,
        "is_trial": 1
    },
    {
        "id": 1599050404885519,
        "is_trial": 1,
        "enable_maintenance_period": 1
    },
    {
        "id": 1606299860676369,
        "validity_period": "2030-01-02",
        "is_trial": 1
    }
]
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "detail": "Licenses Updated."
}
```


[title] Update License Custom Field
[path] Management API/License/Custom Fields/

Updates a license custom field, if requesting manager has access permissions to it.

**URL**: `/api/v1/license-custom-fields/{id}/`

**Method**: `PATCH`

### Parameters:

- `value` - String

### Data Example:

```json
{
    "value": "23"
}
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 83,
    "value": "23",
    "license": 1609234933166159,
    "product_custom_field": 51
}
```


[title] List Orders
[path] Management API/Order/

:::ApiMethodV2
```json
{
  "name": "Show all orders the requesting manager has access permissions to.",
  "method": "GET",
  "url": "/api/v1/orders/",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "lCpk1WBBWA7FghK8v4em3",
        "language": "json",
        "code": "",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "lCpk1WBBWA7FghK8v4em3"
  },
  "results": {
    "languages": [
      {
        "id": "tIlXWYaZ4BhlQrcn2l17E",
        "language": "200",
        "code": "{\n    \"count\": 5,\n    \"next\": null,\n    \"previous\": null,\n    \"results\": [\n        {\n            \"id\": 1593781720493279,\n            \"customer\": {\n                \"id\": 620,\n                \"total_orders\": 14,\n                \"total_licenses\": 45,\n                \"labels\": [\n                    {\n                        \"id\": 3,\n                        \"label_id\": 8,\n                        \"label\": \"Customer\",\n                        \"color\": \"#ff9f43\"\n                    },\n                    {\n                        \"id\": 53,\n                        \"label_id\": 34,\n                        \"label\": \"Loyal\",\n                        \"color\": \"#3a0cd4\"\n                    }\n                ],\n                \"email\": \"tc@tc.com\",\n                \"first_name\": \"\",\n                \"last_name\": \"\",\n                \"company_name\": \"\",\n                \"phone\": \"\",\n                \"reference\": \"\",\n                \"address\": \"\",\n                \"postcode\": \"\",\n                \"city\": \"\",\n                \"country\": \"\",\n                \"state\": \"\",\n                \"clabels_all\": \"customerloyal\",\n                \"cognito_user_pool_id\": \"\",\n                \"metadata\": {},\n                \"company\": 277,\n                \"license_user\": null,\n                \"clabels\": [\n                    8,\n                    34\n                ]\n            },\n            \"customer_account\": null,\n            \"has_active_licenses\": false,\n            \"created_at\": \"2020-07-03T13:08:40Z\",\n            \"updated_at\": \"2020-07-03T13:08:40Z\",\n            \"store_id\": \"d2d2dce02c844d4492c9d48758aa143a\",\n            \"type\": \"normal\",\n            \"customer_email\": null,\n            \"is_test\": false,\n            \"customer_reference\": null,\n            \"is_trial\": false,\n            \"download_id\": null,\n            \"language\": null,\n            \"campaign_params\": null,\n            \"customer_first_name\": null,\n            \"customer_last_name\": null,\n            \"customer_company\": null,\n            \"customer_phone\": null,\n            \"metadata\": {},\n            \"company\": 277\n        },\n        ...\n    ]\n}",
        "customLabel": ""
      },
      {
        "id": "BW_VFo9EAk4BQf596DBVY",
        "language": "404",
        "code": "{\n  \"message\": \"Ain't no cake like that.\"\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "tIlXWYaZ4BhlQrcn2l17E"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "hasTryItOut": false,
  "autoGeneratedAnchorSlug": "show-all-orders-the-requesting-manager-has-access",
  "legacyHash": "DUoWVUSlUkQLi2Zf6XytN"
}
```
:::

### Query Parameters:

### Ordering:

- `order_by` - Which attribute to order the list by.
  - default ordering is ascending, can be made descending by prefixing the attribute name with `-`
  - Example: `order_by=created_at`
  - Example: `order_by=-created_at`

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on order or related to the order.

If available, additional suffixes can be appended to attributes which further define the filter:

1. `__startswith` - string value is a starting substring of the attribute
2. `__icontains` - string value is a substring of the attribute (case insensitive)

Possible filters:

- `store_id__icontains`
- `customer__email`
- `customer__email__startswith`
- `customer__email__icontains`
- `company`
- `customer_id`
- `customer_email`
- `customer_company_name`
- `customer_company_name__icontains`
- `customer_reference__icontains`
- `customer_name__icontains`
- `customer_label__in`
- `customer__account`
- `customer__account__name`
- `customer__account__name__icontains`
- `customer__account__code`
- `customer__account__code__icontains`
- `customer__account__description`
- `customer__account__description__icontains`
- `customer__account__phone`
- `customer__account__phone__icontains`
- `customer__account__address`
- `customer__account__address__icontains`
- `customer__account__email`
- `customer__account__email__icontains`
- `customer__account__reference`
- `customer__account__reference__icontains`
- `customer__account__not`
- `metadata`


[title] 
[path] Management API/License/


[title] Check License
[path] Management API/License/

Checks the validity of license against a certain hardware ID.

**URL**: `/api/v1/licenses/check_license/`

**Method**: `GET`

### Query Parameters:

### Key-Based Licenses:

- `hardware_id`= "123454679824"
- `license_key`= "FC78-D4QH-B6SF-C9AB"
- `product` = `XY`

### User-Based Licenses:

- `hardware_id`= "123454679824"
- `username`= "[**test@email.com**](mailto\:test@email.com)"
- `product` = `XY`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 1699349720166389,
    "order_store_id": "c40cd038ad7d4ae3a79c4d27b9edb4dd",
    "license_active": true,
    "license_enabled": true,
    "license_type": "consumption",
    "license_key": "H4ZH-VL2X-9GJJ-X2J6",
    "is_trial": false,
    "validity_period": null,
    "maintenance_period": null,
    "allow_grace_period": false,
    "grace_period": 0,
    "max_activations": 1,
    "allow_unlimited_activations": false,
    "times_activated": 1,
    "start_date": null,
    "transfer_count": 0,
    "max_transfers": 10,
    "allow_overages": false,
    "max_overages": 0,
    "is_floating_cloud": false,
    "is_floating": false,
    "floating_timeout": 5,
    "can_borrow": false,
    "max_borrow_time": 0,
    "prevent_vm": false,
    "custom_fields": [
        {
            "name": "skr",
            "data_type": null,
            "value": "222"
        },
        {
            "name": "1",
            "data_type": null,
            "value": "1"
        }
    ],
    "product_features": [],
    "customer": {
        "email": "",
        "company_name": "",
        "reference": "",
        "phone": "",
        "first_name": "",
        "last_name": "",
        "city": "",
        "postcode": "",
        "state": "",
        "country": "",
        "customer_account": null,
        "metadata": {}
    },
    "product_details": {
        "product_id": 1683881296184003,
        "product_name": "p",
        "short_code": "p",
        "authorization_method": "license-key",
        "metadata": {}
    },
    "metadata": {},
    "max_consumptions": 8,
    "total_consumptions": 0,
    "allow_unlimited_consumptions": false,
    "reset_consumption": false,
    "consumption_period": null,
    "device_id": 1699349796909409,
    "is_borrowed": false,
    "borrowed_until": null,
    "is_expired": false,
    "version": "",
    "installation_file": "",
    "release_date": "",
    "hash_md5": "",
    "requires_version": "",
    "environment": "",
    "eula_link": "",
    "release_notes_link": "",
    "size": "",
    "channel": "",
    "hardware_id": "1",
    "date": "Thu Nov 9 2023 10:21:23 GMT+0000",
    "offline_signature": "",
    "license_signature": "",
    "license_signature_v2": ""
}
```


[title] List License Features Import Results
[path] Management API/License/Features Import Results/

Show all license features import results the requesting manager has access permissions to.

**URL**: `/api/v1/license-features-import-results/`

**Method**: `GET`

### Query Parameters:

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on customer or related to the customer.

Possible filters:

- `status__iexact`
  - Choices: `pending`, `running`, `error`, `success`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "count": 9,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 12,
            "file_name": "lpf_example.csv",
            "status": "success",
            "created_at": "2021-05-28T07:41:50.247644Z",
            "started_at": "2021-05-28T07:41:58.090021Z",
            "finished_at": "2021-05-28T07:42:03.189833Z",
            "result": {
                "total_row_count": 5,
                "valid_row_count": 5,
                "invalid_rows": [],
                "created_license_features": 5,
                "existed_license_features": 0
            }
        },
        ...
    ]
}
```


[title] Set Activations Data for User
[path] Management API/License/

Sets activations data for a single user, if requesting manager has access permissions to it.

**URL**: `/api/v1/licenses/{id}/set_users_activations/`

**Method**: `POST`

### Data Example:

```json
{
    "2449": {
        "max_activations": 100
    },
    "2452": {
        "reset_total_activations": true
    },
    "2453": {
        "max_activations": 200,
        "reset_total_activations": true
    }
    ,
    "2454": {
        "allow_unlimited_activations": true
    }
}
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "message": "Users activations set."
}
```


[title] /license-features-import-results/
[path] Management API/License/


[title] /installation-files/
[path] Management API/Product/


[title] Security and Cryptographic Providers
[path] SDKs/Tutorials/Advanced Usage/

LicenseSpring prioritizes software security and empowers vendors to bolster their software security.&#x20;

While offering a default cryptographic service provider, we enable software vendors to adapt it according to their needs.&#x20;

This guide outlines changing cryptographic providers, reasons for the change, and a comprehensive security best practices tutorial.

## Prerequisites

1. Completed the [**Getting Started**](docId\:LSFY9tQ3vfq4ROOW9sHkd) Tutorial, specifically:
   - Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
   - Created a `LicenseID` using either `LicenseID::fromKey` or `LicenseID::fromUser` function, depending on the activation method you prefer.
   - Implemented basic license management, including license activations, deactivations, and both online and local license checks.

## Cryptographic Providers

A cryptographic provider, often referred to as a cryptographic library or module, is a software component that offers a collection of cryptographic algorithms and functions to secure data through encryption, decryption, digital signatures, hashing, and more.

### Default Cryptographic Provider

Certain LicenseSpring SDKs utilize a license file stored locally on the user's device for the purpose of validating their license status. This file serves as a repository for crucial license-related information as well as user data.&#x20;

To maintain the security of this data, every time a license file is generated, it undergoes encryption through our proprietary cryptographic provider.&#x20;

Subsequently, during the program's execution, the cryptographic provider facilitates the decryption of the license file, rendering the enclosed data usable within the program.

For security considerations, we are unable to divulge specifics about the underlying algorithm of our default cryptographic provider. However, we do offer mechanisms to enhance the sense of security for users, ensuring their confidence in the robustness of the cryptographic provider.

For information on when default encryption and decryption occurs, see [**Custom License Storage**](docId:5rgmpnpkkSyPdlzaWVlHz).

### Changing Cryptographic Provider

Our C++ and .NET SDKs offer diverse options for enhancing security by customizing the default cryptographic provider. You have the flexibility to modify the default cryptographic provider by implementing the designated interface found in both the C++ and .NET SDKs. However, for a more straightforward approach, you can maintain the default cryptographic provider and instead alter the salt and key used.

In simpler terms, a key functions similarly to a password, enabling data encryption and decryption. On the other hand, a salt is appended to your data to increase the complexity of decryption. This adjustment lets you distinguish your encryption method from the default approach in a straightforward manner.

:::hint{type="warning"}
We highly recommend setting a unique salt for all new products that are using LicenseSpring. This way, encryption will be different for each product.
:::

While we entrust the implementation of the interface to developers, as it depends on their encryption preferences, we will demonstrate here how to establish the salt and key for the default cryptographic provider. It's advisable to configure the cryptographic provider early in your application, alongside the other license settings, to ensure that it's in place before activation. This proactive approach ensures the encryption of your local license file using the designated cryptographic provider.

The following can be used to specifically set the key and salt:

:::CodeblockTabs
```cpp
ExtendedOptions options;
options.getCryptoProvider()->setKey( "KEY" );
options.getCryptoProvider()->setSalt( "SALT" );

auto configuration = Configuration::Create(
        EncryptStr( "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" ),
        EncryptStr( "XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX" ),
        EncryptStr( "XXXXXX" ),
        "NAME", "VERSION", options );
        
auto licenseManager = LicenseManager::create( pConfiguration );
```

```csharp
var options = new LicenseSpring.ExtendedOptions();

var configuration = new LicenseSpring.Configuration(
            apiKey: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
            sharedKey: "XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX", 
            productCode: "XXXXXX", 
            appName: "NAME",
            appVersion: "VERSION",
            extendedOptions: options );
            
configuration.CryptoProvider.Key = "KEY";
configuration.CryptoProvider.Salt = "SALT";

var licenseManager = LicenseManager.GetInstance();

licenseManager.Initialize( configuration );
```

````swift
/// LicenseCryptor is protocol declared in SDK to implement custom license encryption routines.
///
/// ```
/// @objc
/// public protocol LicenseCryptor {
///     func encrypt(_ data: Data) -> Data?
///     func decrypt(_ data: Data) -> Data?
/// }
/// ```

struct MyCryptor: LicenseCryptor {
    func decrypt(_ data: Data) -> Data? {
        ...
        return decrypted
    }
    
    func encrypt(_ data: Data) -> Data? {
        ...
        return encrypted
    }
}
configuration.licenseCryptor = MyCryptor()
````

```python
## SETUP (ONLY ONCE)
from licensespring.licensefile.default_crypto import DefaultCryptoProvider
from licensespring.licensefile.config import Configuration
from licensespring.licensefile.license_manager import LicenseManager

password = "YOUR_PASSWORD"
salt = "YOUR_SALT"


crypto = DefaultCryptoProvider()

key = crypto.derive_key(password=key_password,salt=key_salt)
iv = crypto.generate_random_iv()


conf = Configuration(product="your_product_key",api_key="your_api_key",
                   shared_key="your_shared_key",file_key=key,file_iv=iv,
                   is_guard_file_enabled=True)
                   
manager = LicenseManager(conf)
```

```go
// Go SDK v2
	storage := &data_handler.DefaultFileStorage{}
	crypto := crypto_provider.DefaultCryptoProvider{}
	if useOAuth {
		crypto.SetKey(config_file.CryptoProviderKey)
	} else {
		crypto.SetKey(config_file.SharedKey)
	}
	storage.SetCryptoProvider(&crypto)

	c := license_handler.LicenseHandlerConfig{
		ApiKey:      config_file.ApiKey,
		SharedKey:   config_file.SharedKey,
		ProductCode: productCode,
		AuthData:    auth.FromKey(productAuth.LicenseKey),
		OAuth:       useOAuth,
		Verbose:     logger.VERBOSE,
		Storage:     storage,
	}

	lh, err := license_handler.NewLicenseHandler(c)

```
:::

:::hint{type="info"}
**Note:&#x20;**&#x41;fter this code snippet, the rest of your program that uses `licenseManager`, including activation and file reading, will use this cryptographic provider for encryption/decryption.
:::

In the C++ SDK, there is a setter for `CryptoProvider`:

```cpp
options.overrideCryptoProvider( cryptoProvider );
```

:::hint{type="info"}
**Note:** If the crypto provider is not set, then the default crypto provider will be used.
:::

### Why Change Cryptographic Provider?

Introducing a customized encryption and decryption algorithm is relevant if your product already employs a specific encryption algorithm that you wish to maintain uniform across your software, including licensing components.&#x20;

Moreover, developers have the liberty to adopt this approach if they hold reservations about utilizing an external encryption algorithm and instead prefer to develop and integrate their own encryption methodology.&#x20;

This level of autonomy empowers developers to align encryption practices with their individual security considerations and preferences.

## Other Security Features

### Encrypting Strings

In C++, the potential exists to extract strings from an application after it has been compiled.&#x20;

This can potentially expose sensitive information, such as API keys, shared keys, management keys, product codes, and various other strings of value. This vulnerability underscores the importance of safeguarding these strings.&#x20;

Fortunately, the C++ SDK offers a solution: the `EncryptStr()` method encrypts these strings during compile-time and decrypts them during run-time.

Embracing this method is highly advisable for constant strings that necessitate shielding from user access.&#x20;

By employing this approach, you can significantly enhance the security of your application's sensitive information, ensuring that these strings remain well-protected throughout the application's lifecycle.

```cpp
auto configuration = Configuration::Create(
        EncryptStr( "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" ),
        EncryptStr( "XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX" ), 
        EncryptStr( "XXXXXX" ),
        "NAME", "VERSION", options );
```

### Logging

While logging serves as a valuable tool for debugging purposes, it holds utmost significance to disable logging in your release build. Failing to do so could potentially expose users to any information that has been logged. The nature of this information can encompass a wide array of data.&#x20;

For a comprehensive understanding of the type of information that could be at risk, we recommend referring to our [**Logging**](docId\:xpH0cdnbqdfjM1kYooptZ).

By deactivating logging in your release build, you take a crucial step toward safeguarding user privacy and preventing unintended exposure of sensitive data. This practice contributes to the overall security and integrity of your software product.

### License Security

Implementing license checks, whether conducted offline or online, during both application opening and closing is highly advisable.&#x20;

These checks play a pivotal role in verifying the ongoing validity of a license and ensuring its integrity remains intact.&#x20;

Such measures are especially effective in thwarting potential tampering attempts, such as altering the date to extend license validity artificially or transferring an activated license file to an unauthorized device lacking the corresponding license.

### Air-Gapped Licensing

In zero-trust networks, where security is a top priority and trust assumptions are minimized, adopting [**Air-Gapped Licensing**](docId\:cgPsVOYMM4d4C4iohILhS) can offer substantial advantages.&#x20;

Air-gapped licensing involves keeping the licensing process entirely isolated from external networks and internet connectivity. This approach enhances security by reducing the potential attack surface and preventing unauthorized access to licensing components.

[title] Offline Licensing
[path] SDKs/Tutorials/Licensing Scenarios/

In certain scenarios, some computers may **lack an active internet connection** or be behind a restrictive firewall, hindering online activation.&#x20;

To address this, we have developed a mechanism that enables the activation and deactivation of licenses in an offline environment.

## Prerequisites

1. Completed the [**Getting Started**](docId\:LSFY9tQ3vfq4ROOW9sHkd) Tutorial, specifically:
   - Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
   - Created a `LicenseID` using either `LicenseID::fromKey` or `LicenseID::fromUser` function, depending on the activation method you prefer.

Performing offline license activation using the LicenseSpring SDKs is a straightforward process. Follow the steps below to activate and deactivate licenses:

**License Activation Process:**

1. Generate a request file by calling the `createOfflineActivationFile` function of `LicenseManager`. Provide the `LicenseID` you created earlier and specify the path where you want to save the request file. The function will return the path to the created file.
2. Open the [**offline activation page**](https://offline.licensespring.com) and upload the request file you generated in the previous step. Once uploaded, download the offline activation file from this page.
3. Activate the license by calling the `activateLicenseOffline` function of `LicenseManager` and passing the path to the offline activation file received from the website. The function will return a `License` object upon successful activation, or null if the activation process fails.&#x20;

**License Deactivation Process:**

1. Call the `deactivateOffline` function of the `License` object, and optionally provide the path where you want to save the deactivation request file. The function will return the path to the created file.
2. Call the `clearLocalStorage` function of `LicenseManager` to delete the files created by the SDK to store license data.
3. Open the [**offline activation page**](https://offline.licensespring.com/) and upload the deactivation request file you generated in the previous step. Once uploaded, you will receive a message confirming that the license has been deactivated.

Let's get started!

## Offline Activation Process

### Request File Creation

To initiate offline license activation, the first step involves creating an offline activation request file.&#x20;

You can accomplish this by utilizing the following function:

:::CodeblockTabs
```cpp
auto filePath = licenseManager->createOfflineActivationFile( licenseId );
```

```csharp
string filePath = licenseManager.GetOfflineActivationFile(licenseId);
```

```swift
let fileLocation = try manager.createOfflineActivationFile(licenseKey: "XXXX-XXXX-XXXX-XXXX")
```

```python
req_file_path = manager.create_offline_activation_file(license_id,'offline_files/test')

print(req_file_path)
```

```go
// Go SDK v2
offlineActivationData, path, err := license_handler.CreateOfflineActivationFile("path")
```

```java
LicenseIdentity identity = LicenseIdentity.fromKey("<LICENSE-KEY>");
String filePath = licenseManager.offlineActivationFile(identity, "pathToOutput");
```
:::

The provided function generates an offline activation request file for the specified key-based/user-based license, identified by `LicenseID`.&#x20;

If you include a 'path' parameter, the file will be created with the specified path and name.&#x20;

:::hint{type="info"}
**Note:** If 'path' is not provided, the default location for the offline activation request file will be the desktop, and the default name will be "ls\_activation.req": C:\Users%USERNAME%\Desktop\ls\_activation.req.
:::

### Uploading the Request to the Offline Activation Portal

Once you have generated your offline activation request file, the next step is to upload it to the [**LicenseSpring offline portal**](https://offline.licensespring.com/). It's essential to note that this process requires a computer with online access.



![LicenseSpring Offline Portal](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/OgqhTaqlVrxlP_NqQHgsf_image.png "LicenseSpring Offline Portal")

Upon uploading the request file, you will receive an offline activation response file named "ls\_activation.lic." This response file will enable you to proceed with the offline activation process successfully.

### Activation With a Response File&#x20;

To complete the offline activation process on a device, utilize the function `activateLicenseOffline(path)` as demonstrated below:

:::CodeblockTabs
```cpp
license = licenseManager->activateLicenseOffline( path );
```

```csharp
ILicense license = licenseManager.ActivateLicenseOffline(filePath);
```

```swift
let responseFile: URL = ...
let license = try manager.activateLicenseOffline(responseFile)
```

```python
license = manager.activate_license_offline('path_to_lic_file/ls_activation.lic')
```

```go
// Go SDK v2
ld, err := license_handler.ActivateLicenseOffline(path)
```

```java
LicenseIdentity identity = LicenseIdentity.fromKey("<LICENSE-KEY>");
License license = licenseManager.activateOfflineResponse(identity, "pathToFile");
```
:::

In the 'path' parameter, provide the name and path of the offline activation response file.&#x20;

If 'path' is left empty, the function will search for the response file named "ls\_activation.lic" on the desktop by default: C:\Users%USERNAME%\Desktop\ls\_activation.lic.

By running this, you will have successfully activated the license offline on the device.

There is a checker for if the license is offline activated also, as shown below:

:::CodeblockTabs
```cpp
bool offlineActivatedTest = license.isOfflineActivated();
```

```csharp
bool offlineActivatedTest = license.IsOfflineActivated();
```

```swift
license.isOfflineActivated
```

```java
boolean isOfflineActivated = license.isOfflineActivated();
```
:::

This Boolean checker returns true if offline activated, and false if not.

### *How to Secure Offline Activation With ExtendedOptions::enableGuardFile&#x20;*

Guard files **prevent users from using the same license request file** and are automatically enabled within `ExtendedOptions`.&#x20;

Guard files can be disabled in the `ExtendedOptions` constructor or by running the following method, where options is an `ExtendedOptions` object:

:::CodeblockTabs
```cpp
options.enableGuardFile( false );
```

```csharp
extendedOptions.ProtectOfflineActivation = false;
```

```python
from licensespring.licensefile.config import Configuration

conf = Configuration(product="your_product_key",api_key="your_api_key",
                   shared_key="your_shared_key",file_key=key,file_iv=iv,
                   is_guard_file_enabled=True)
```
:::

Once enabled, LicenseSpring generates a guard file in the same folder where the license and SDK logs are stored.&#x20;

This guard file remains hidden and plays a crucial role in safeguarding the licensing process. Should anyone attempt to remove or alter this file, the license activation will fail as a protective measure.

The guard file is automatically created when you generate the request file for offline activation.&#x20;

It must remain valid and present when a user submits the response file to ensure a successful activation process. The presence of the guard file is pivotal for maintaining the integrity and security of the offline activation procedure.

To determine the current status of the guard file, you can utilize the following method (where `options` is an `ExtendedOptions` object):

:::CodeblockTabs
```cpp
bool guardFileTest = options.isGuardFileEnabled();
```

```csharp
bool guardFileTest = options.ProtectOfflineActivation;
```
:::

If a guard file is actively protecting the offline activation process `guardFileTest` returns true.

This method also exists within the `Configuration` object, so using the following (where `config` is a `Configuration` object) will yield an identical result:

```cpp
bool guardFileTest = config.isGuardFileEnabled();
```

## Offline License Update

### How to Get a Refresh File

Offline license refresh allows users to update their activated offline license, which is typically used when certain aspects of the license have been modified on the backend.&#x20;

For instance, you might want to add a new feature without requiring license reactivation.&#x20;

To perform an offline license refresh, locate the license on the LicenseSpring Platform and access the `Devices` tab.



![Downloading License Refresh File](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/DJEkTXqRqDiNrdZ-vVZpl_image.png "Downloading License Refresh File")

### UpdateOffline Method Usage

The line of code responsible for the update is as follows:

:::CodeblockTabs
```cpp
license->updateOffline( path );
```

```csharp
bool isUpdated = license.UpdateOffline(filePath);
```

```swift
let updateFile: URL = ...
try license.updateOffline(with: updateFile)
```

```python
license.update_offline('offline_files/license_refresh.lic',False) 
```
:::

In the `path` parameter, you should provide the path to the `license_refresh.lic` file, which you downloaded from the page, as shown above.

`updateOffline` also has a secondary optional parameter, `resetConsumpion`, which is disabled by default. If this parameter is set to true, then this update also resets the consumption.

This method returns true if the license is successfully updated, and false otherwise.

## Offline Deactivation

### How to Create Deactivation Request File

Once a license has been activated, it can also be deactivated through a similar process. The function responsible for creating the offline deactivation request file is as follows:

:::CodeblockTabs
```cpp
auto filePath = license->deactivateOffline();
```

```csharp
string filePath = license.DeactivateOffline(deactivationRequestFilePath);
```

```swift
let request = try license.deactivateOffline()
```

```python
license.deactivate_offline('path_where_to_create_req_file')
```

```go
// Go SDK v2
ld, deactivationReq, path, err := license_handler.DeactivateOffline("path")
```
:::

Additionally, you have the option to provide an alternative path as an optional parameter to the `deactivateOffline` function, where the deactivation request file will be created and stored.&#x20;

:::hint{type="info"}
**Note:&#x20;**&#x49;f you leave this parameter empty, the default file path will be used, saving the file to the desktop.
:::

### Deleting Local License File

To eliminate any local license data, after creating the deactivation file, we execute the following:

:::CodeblockTabs
```cpp
licenseManager->clearLocalStorage();
```

```csharp
licenseManager.ClearLocalStorage();
```

```swift
try manager.clearLocalStorage()
```

```python
manager.clear_local_storage()
```
:::

By performing these steps, you can efficiently deactivate the license and clear any associated local data.

## Code Sample&#x20;

### Loading Local License and Creating Offline Activation Request File

First we load the local license, using `getCurrentLicense` whilst checking for any local license errors:

:::CodeblockTabs
```cpp
try
    {
        license = licenseManager->getCurrentLicense();
    }
    catch ( LocalLicenseException )
    { 
        //Cannot read the local license or the local license file is corrupt
    }
auto filePath = licenseManager->createOfflineActivationFile( licenseId );
     //Request file created at filePath
     //Upload request file to the LicenseSpring portal to get response file.
```

```csharp
    try
    {
        license = licenseManager.CurrentLicense();
    }
    catch ( LocalLicenseException ex )
    { 
        //Cannot read the local license or the local license file is corrupt
    }
string filePath = licenseManager.GetOfflineActivationFile(licenseId);
     //Request file created at filePath
     //Upload request file to the LicenseSpring portal to get response file.
```

```python
manager = LicenseManager(conf)
    
try:
    license = manager.load_license()

except Exception as ex:

    print(ex)

```
:::

Similarly to creating a deactivation request file, we can select a path for this file to be created or use the default path by leaving the path as null in `createOfflineActivationFile( licenseID, path )`.

:::hint{type="info"}
**Note:&#x20;**&#x49;f the `path` parameter is null, then the default path that `createOfflineActivationFile( licenseID )` creates the file at is: **'C:\Users\\%USERNAME%\Desktop\ls\_deactivation.req'**.
:::

### Activating Offline License Using Activation Response File

Now that we have submitted the offline activation file to the portal and downloaded the activation response file, we must activate our device locally.

After checking that our local license is not active, we run `activateLicenseOffline( path )`.

:::CodeblockTabs
```cpp
if ( license == nullptr ) 
  {
    try
      {
        license = licenseManager->activateLicenseOffline( path );
      }
    catch ( SignatureMismatchException )
      {
        //Signature inside activation file is not valid." << std::endl;
      }
```

```csharp
if(licenseManager.CurrentLicense() == null)
{
    try
    {
       License license = licenseManager.ActivateLicenseOffline(licenseFilePath);
    }
    catch (SignatureMismatchException ex)
    {
       // handle exceptions
    }
}
```

```python
manager = LicenseManager(conf)
try:

    license = manager.activate_license_offline('path_to_lic_file/ls_activation.lic')

except Exception as ex:

    print(ex)
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x49;f the `path` parameter is null, then the default path that `activateLicenseOffline` searches for the file is: **'C:\Users\\%USERNAME%\Desktop\ls\_deactivation.req'**.
:::



### Local License Check

To verify the license locally on the device without connecting to the backend, we utilize the `localCheck` function in the following manner:

:::CodeblockTabs
```cpp
if ( license != nullptr )
  {
    license->localCheck();
  }
```

```csharp
if(license != null)
{
   license.LocalCheck();
}
```

```python
license.local_check()
```
:::

If `license` is a `nullptr`, it indicates that a local license **does not exist**. Therefore, it is crucial to first confirm the existence of a local license before proceeding with any operations related to the license.&#x20;

The `localCheck` function also throws exceptions to indicate any encountered issues.&#x20;

This feature proves beneficial in assessing the license's validity and detecting potential license tampering. If any irregularities are detected, the function will throw an exception.

To ensure license integrity, it is considered best practice to perform a `localCheck` (offline check) during each startup.&#x20;

This practice helps confirm that the license file has not been copied from another computer and that the license is in a valid state.

A code sample that handles all potential exceptions is also provided below:

:::CodeblockTabs
```cpp
if ( license != nullptr )
    {
        try
        {
            license->localCheck();
        }
        catch ( LicenseStateException )
        {
            //License Invalid
            if ( !license->isActive() )
                //License Inactive
            if ( license->isExpired() )
                //License Expired
            if ( !license->isEnabled() )
                //License Disabled
        }
        catch ( ProductMismatchException )
        {
            //License does not belong to configured product.
        }
        catch ( DeviceNotLicensedException )
        {
            //License does not belong to current computer.
        }
        catch ( VMIsNotAllowedException )
        {
            //Currently running on VM, when VM is not allowed.
        }
        catch ( ClockTamperedException )
        {
            //Detected cheating with system clock.
        }
    }
```

```csharp
if (license != null)
{
   try
   {
      license.LocalCheck();
   }
   catch (LicenseInactiveException)
   {
      // License is inactive.
   }
   catch (LicenseDisabledException)
   {
      //License is disabled.
   }
   catch (LicenseExpiredException)
   {
      // License is expired.
   }
   catch (ProductMismatchException)
   {
      //License does not belong to configured product.
   }
   catch (DeviceNotLicensedException)
   {
      //License does not belong to current computer.
   }
   catch (VMIsNotAllowedException)
   {
       //Currently running on VM, when VM is not allowed.
   }
   catch (ClockTamperedException)
   {
      //Detected cheating with system clock.
   }
}
```

```python
try:

    license.local_check()

except Exception as ex:

    print(ex)

```
:::

### Offline Update

To update licenses offline, we use the `updateOffline( path )` method as shown below, where `license` is a `license` object.

:::CodeblockTabs
```cpp
if ( license->updateOffline( path ) )
  {
    //License succesfully updated.
  }
else
  //License could not be updated.
          
```

```csharp
if (license.UpdateOffline(path))
{
  //License succesfully updated.
}
else
  //License could not be updated.
```

```python
if license.update_offline('offline_files/license_refresh.lic',False):
    pass
 
else:
    pass
```
:::

Just like the previous code sample, we can also first check whether `license` is a `nullptr` to confirm the local license exists before we attempt to update it.

We can also handle the specific exceptions thrown by `updateOffline( path )` as shown below:

:::CodeblockTabs
```cpp
if ( license == nullptr ) 
    //Cannot refresh an inactive license.
else
  {
    try 
      {
        if ( license->updateOffline( path ) )
          {
            //License succesfully updated.
          }
        else
          {
            //License could not be updated.
          }
      }
    catch ( SignatureMismatchException )
        {
          //Device does not match update file's device signature.
        }
    catch ( LocalLicenseException )
        {
          //Local license file cannot be read, may be corrupted.
        }
    catch ( ProductMismatchException )
        {
          //License product code doesn't match configuration product code.
        }
    catch ( DeviceNotLicensedException )
        {
          //License refresh file does not correspond to current device.
        }
    } 
```

```csharp
if (license != nullptr)
{
  try 
  {
    if (license.UpdateOffline(path))
    {
      //License succesfully updated.
    }
    else
    {
      //License could not be updated.
    }
  }
  catch (FileNotFoundException)
  {
    //If file cannot be found.
  }
  catch (InvalidDataException)
  {
    //If file content is empty or invalid.
  }
  catch (SignatureMismatchException)
  {
    //In case signature in the file is not valid or missing.
  }
} 
```

```python
try:
    if license.update_offline('offline_files/license_refresh.lic',False):
        pass
       # license updated!

    else:
        pass

except Exception as ex:

    print(ex)
```
:::

### License Deactivation

To deactivate a license offline, first ensure that the license is currently active. Then an offline deactivation request file will be created at the path defined in the parameter of `deactivateOffline( path )`.

:::hint{type="info"}
**Note:&#x20;**&#x49;f the `path` parameter is null, then the default path that `deactivateOffline()` creates the file at is: **'C:\Users\\%USERNAME%\Desktop\ls\_deactivation.req'**.
:::

After creating the offline deactivation request file, it is vital that the local license file is deleted, using `clearLocalStorage`.

A full code sample is as follows:

:::CodeblockTabs
```cpp
if ( license != nullptr && license->isActive() )
  {
    try
      {
        auto filePath = license->deactivateOffline( path );
      }
    catch ( LocalLicenseException )
      {
        //Local license file cannot be read, may be corrupted.
      }
    licenseManager->clearLocalStorage();
    //To finish deactivation process, upload deactivation request file to the LicenseSpring portal.
  }
else
    //License is already deactivated.
```

```csharp
if (license != null && license.Status().IsActive())
  {
    try
      {
        string filePath = license.DeactivateOffline(path);
      }
    catch (LocalLicenseException)
      {
        //Local license file cannot be read, may be corrupted.
      }
    licenseManager.ClearLocalStorage();
    //To finish deactivation process, upload deactivation request file to the LicenseSpring portal.
  }
else
    //License is already deactivated.
```

```python
if license.license_active():
    try:
        path = license.deactivate_offline("path")
            
    except Exception as ex:
        print(ex)
        
    manager.clear_local_storage()

```
:::

## Automating Offline Licensing

Automating the offline activation process becomes achievable by utilizing the following API endpoints:

- [**Offline Activation**](https://docs.licensespring.com/H_VE-license-api/activation-deactivation/offline-activation)
- [**Offline Deactivation**](https://docs.licensespring.com/license-api/activation-deactivation/offline-deactivation)

These endpoints provide developers with the necessary tools to seamlessly manage offline license activation, enabling users to access and activate licenses without relying on a constant internet connection.&#x20;

:::hint{type="info"}
**Note:&#x20;**&#x49;f you want to use these API endpoints directly, instead of using the SDK, please [**contact us**](https://licensespring.zendesk.com/hc/en-us/requests/new) for additional instructions.
:::

## Troubleshooting

### Exceptions Related to Offline Activation

Exceptions that might occur when performing offline license activation:

- **SignatureMismatchException:&#x20;**&#x53;ignature inside activation file is not valid.
- **LocalLicenseException:&#x20;**&#x49;nvalid activation file provided.
- **ProductMismatchException:&#x20;**&#x4C;icense product code does not correspond to configuration product code.
- **DeviceNotLicensedException:&#x20;**&#x4C;icense file does not belong to the current device.

### Why is the License File Not Generated After Uploading the Request File?

The offline license activation process may encounter failure due to any of the following reasons:

1. Total activations on the account have reached the maximum limit.
2. The license is expired or disabled.
3. Incorrect license credentials provided during activation.
4. Incorrect product configuration, such as using a shared key, API key, or product code.
5. The license is associated with an account using the free tier.


[title] Handling Product Versions
[path] SDKs/Tutorials/Best Practices/

Product versioning empowers vendors to introduce fresh iterations of their licensed products, fostering increased customization.&#x20;

This article serves to educate readers on a range of topics, including defining and retrieving application versions, implementing conditional update checks within maintenance windows, validating product versions during license checks, and other relevant insights.

## Prerequisites

1. Completed the Getting Started tutorials, specifically:
   - Initialized LicenseManager (or LicenseHandler) with your configuration using the appropriate settings.
   - Activated a license.

## Defining App Version

Setting application version is completed within the `Configuration` constructor, as shown below:

:::CodeblockTabs
```cpp
std::shared_ptr<Configuration> pConfiguration = Configuration::Create( 
  EncryptStr( "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" ),
  EncryptStr( "XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX" ), 
  EncryptStr( "XXXXXX" ), 
  appName, appVersion, options );
```

```csharp
var configuration = new LicenseSpring.Configuration(
  apiKey: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  sharedKey: "XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX",
  productCode: "PRODUCT SHORT CODE",
  appName: "My application",
  appVersion: "v5.2" );
```

```java
LicenseSpringConfiguration configuration = LicenseSpringConfiguration.builder()
                .apiKey( "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" )
                .productCode( "javaproduct" )
                .sharedKey( "XXXXXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXX" )
                .appName( "NAME" )
                .appVersion( "VERSION" )
                .build();
```

```swift
let configuration = Configuration(
    apiKey: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    sharedKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    productCode: "XX"
)
configuration.appName = "My LicenseSpring Application"
configuration.appVersion = "1.0.0"
```

```python
import licensespring

licensespring.app_version = "MyApp 1.0.0"
```
:::

The fifth parameter passed, `appVersion`, is where the version is set for the application.

From here, current app version can be accessed with:

:::CodeblockTabs
```cpp
appVersion = pConfiguration->getAppVersion();
```

```csharp
appVersion = pConfiguration.AppVersion();
```

```java
appVersion = pConfiguration.getAppVersion();
```

```swift
configuration.appVersion
```
:::

To access a list of all available product versions, we can use `getVersionList()` from the `LicenseManager` object. Acquiring a vector of strings containing all versions is done with:

:::CodeblockTabs
```cpp
listVersions = licenseManager->getVersionList( licenseId );
```

```csharp
listVersions = licenseManager.GetAllVersions( licenseId );
```

```java
listVersions = licenseManager.getVersions( licenseIdentity );
```

```swift
let versions = try license.requestAvailableVersions() // [AvailableVersion].
```

```python
response = manager.get_version_list(license_id=license_id)
```
:::

## Retrieving Installation Files

### Getting Latest Installation File During Online License Check

To confirm the latest product version during a license check, we'll construct an `InstallationFile` object and assign it the value obtained from `license->check()`.&#x20;

As `license->check()` furnishes the most recent `InstallationFile` associated with the license, we can subsequently access the version information by executing:

:::CodeblockTabs
```cpp
InstallationFile::ptr_t ins = license->check();
std::string version = ins->version();
```

```csharp
InstallationFile::ptr_t ins = license.Check();
std::string version = ins.Version();
```

```swift
try license.fullCheck()
if let installationFile = license.installationFile { ... }
```
:::

### Getting All Installation Files

Developers can also retrieve the latest `InstallationFile` releases through the `LicenseManager` object through use of the `licenseID` as follows:

:::CodeblockTabs
```cpp
licenseManager->getInstallationFile( licenseID );
```

```csharp
licenseManager.GetInstallationFile( licenseID );
```

```java
licenseManager.getInstallationFile( licenseIdentity );
```

```swift
let specificVersion = try license.requestInstallationFile(version: "x.y.z")
```

```python
response = manager.get_installation_file(license_id=license_id)

print(response)
```
:::

:::hint{type="info"}
**Note:**

The **C++** `getInstallationFile()` method has two additional, optional parameters. The second parameter is to declare a desired product version, if not provided then the last available version will be assumed. The third parameter is a `InstallFileFilter` object that can be used to filter install files by environment and channel.

The **.NET&#x20;**&#x53;DK has one additional parameter, an `InstallationFileOptions` object that can be used to filter install files by channel or environment, as well as the needed version.
:::

:::hint{type="danger"}
**Exceptions** called if an installation file is not found for requested app version:

**C++:&#x20;**&#x50;roductVersionException

**.NET:&#x20;**&#x41;ppVersionNotFoundException

**Java:&#x20;**&#x4C;icenseSpringException
:::

### InstallationFile Class Overview and Intermediate Updates

The `InstallationFile` class holds crucial information about a product's installation file.&#x20;

It captures details about the product installer or setup file uploaded via the LicenseSpring platform or Management API, facilitating efficient product versioning and management.

Installation files can be used to regulate intermediate updates through accessing the required app version to complete the update

An intermediate update denotes an update that mandates a specific version of the predictor to be presently installed.&#x20;

You can verify the necessary version by utilizing `InstallationFile` as follows:

:::CodeblockTabs
```cpp
requiredVersion = installationFile->requiredVersion();
```

```csharp
requiredVersion = installationFile->RequiredVersion();
```

```swift
if let requiredVersion = installationFile.requiredVersion { ... }
```
:::


[title] Error Handling
[path] SDKs/Tutorials/Best Practices/

Error handling is an integral part of software development. This article provides effective ways to handle LicenseSpring errors and keep your application secure.

## Prerequisites

1. Completed the [**Getting Started**](docId\:LSFY9tQ3vfq4ROOW9sHkd) Tutorial, specifically:
   - Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
   - Created a `LicenseID` using either `LicenseID::fromKey` or `LicenseID::fromUser` function, depending on the activation method you prefer.
   - Implemented basic license management, including license activations, deactivations, and both online and local license checks.

## Handling Exceptions

Methods of **License&#x20;**&#x61;nd **LicenseManager** classes throw exceptions if something went wrong. Put the methods that can produce exceptions in `try...catch` block.

**LicenseSpringException&#x20;**&#x69;s the base class of all SDK exceptions. The good practice is to implement separate logic for different types of exceptions. Below is the example of handling device id mismatch. Instead of closing the application, we can try to upgrade to a new device id algorithm. See: [**Hardware ID generation**](docId\:yFnuCniXYZAno8e-sY5I1)

:::CodeblockTabs
```cpp
try
{
    license->localCheck();
}
catch( const DeviceNotLicensedException& ex )
{
    // Handling specific error: trying to upgrade to new device id algorithm
    license = m_licenseManager->relinkLicense( WinCryptographyId );
    return;
}
catch( const LicenseSpringException& ex )
{
    std::cout << "LicenseSpring exception encountered: " << ex.what();
}
```

```csharp
try
{
    license.LocalCheck();
}
catch( DeviceNotLicensedException ex )
{
    // Handling specific error: trying to upgrade to new device id algorithm
    license = manager.RelinkLicense( DeviceIDAlgorithm.Gen3 );
    return;
}
catch (LicenseSpringException ex )
{
    Console.WriteLine( "LicenseSpring exception encountered: {0}", ex.Message );
}
```

```java
try {
    license.LocalCheck();
} catch(LicenseExpiredException e) {
    // Handling specific error
} catch (LicenseSpringException ex ) {
    System.out.println("LicenseSpring exception encountered: " + ex.getMessage());
}
```
:::

### Common Exceptions

Below is the list of the exceptions that can occur on any SDK request:

| Exception                                                                          | Definition                                                                                                                                    |
| ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `LicenseStateException`                                                            | License is disabled, was reset or expired                                                                                                     |
| `SignatureMismatchException`                                                       | In case signature returned by LicenseSpring server is not valid. E.g. if the response data was changed.                                       |
| `NoInternetException`<br />`NetworkTimeoutException`<br />`LicenseServerException` | Connection-related errors: if there's no Internet or an internal server error occured. See [**License Checks**](docId\:ie-DAh13B4dqxMAQoYgrj) |
| `ApiKeyException`                                                                  | If provided api key cannot be used for the request( is invalid, readonly or revoked).                                                         |
| `AuthorizationException`                                                           | Authorization failed, please check your proxy settings.                                                                                       |

## Handling C++ Errors

The **LicenseHandler** class of C++ SDK is exception-free by default. It provides an alternative way to implement licensing without exceptions but C-style error codes. Make sure to put error checks after **LicenseHandler** calls. 

To retrieve the error use the following methods:

```cpp
bool LicenseHandler::wasError() const; //check if there was an error
LSErrorCode LicenseHandler::getLastError() const; //get code of the last error
const std::string& LicenseHandler::getLastErrorMsg() const;//get message of the last error
```

This class also contains several methods to check for error type, e.g. `isLicenseStateError`, `isNoInternetError`.

Example of handling **LicenseHandler&#x20;**&#x65;rrors:

```cpp
licenseHandler.checkLicenseLocal();
if( licenseHandler.wasError() )
{
    if( licenseHandler.getLastError() == eDeviceError )
        licenseHandler.relinkLicense( WinCryptographyId );
    else
        std::cout << "LicenseSpring error encountered: " << licenseHandler.getLastErrorMsg();
}
```

### Common Errors

Below is the list of the exceptions that can occur on any SDK request:

| Error                                                                                         | Definition                                                                                                                                    |
| --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `eStdError`                                                                                   | C++ standard exception encountered                                                                                                            |
| `eSignatureMismatchError`                                                                     | Server signature is not valid. E.g. if the response data was changed.                                                                         |
| `eNoInternetError`<br />`eNetworkTimeoutError`<br />`eServerError`                            | Connection-related errors: if there's no Internet or an internal server error occured. See [**License Checks**](docId\:ie-DAh13B4dqxMAQoYgrj) |
| `eInvalidApiKey`<br />`eReadOnlyApiKey`<br />`eRevokedApiKey`<br />`eApiKeyProductNotAllowed` | If provided api key cannot be used for the request( is invalid, readonly or revoked).                                                         |
| `eAuthorizationError`                                                                         | Authorization failed, please check your proxy settings.                                                                                       |

## Handling Swift errors

Swift SDK uses `LSError` compatible with `NSError` for error reporting.

Any SDK method marked as `throws`produces `LSError` in case of error.
Possible error codes described as `enum LSErrorCode`.

:::CodeblockTabs
Swift

```swift
do {
    try license.fullCheck()
} catch let error as LSError {
    print("LicenseSpring error: \(error)")
} catch {
    print("Unknown error: \(error)")
}
```
:::


[title] SDK Distribution and Licensing
[path] SDKs/Java SDK/

## SDK License

The following SDK license comes with every distribution (License Client, Floating Client, Management SDK) under `/META-INF/LICENSE`:

```markdown
LicenseSpring Compiled SDK License Agreement (LCSLA)

Preamble:
This LicenseSpring Compiled SDK License Agreement (LCSLA) governs the use, distribution, and modification of the compiled binaries for the LicenseSpring SDKs. These SDKs, including those for C++, Java, and .NET, are designed to facilitate integration with LicenseSpring’s license management service. By accessing or using the SDK binaries, you agree to the terms and conditions set forth in this agreement.

1. Permissions:

	* You are permitted to use the compiled SDK binaries provided by LicenseSpring solely for the purpose of integrating your products with the LicenseSpring service.
	* You may create derivative works that rely on or incorporate the SDK binaries, provided such derivative works are used exclusively as part of the LicenseSpring service.

2. Distribution:

	* You may distribute software that integrates or incorporates the SDK binaries, provided the software interacts directly with the LicenseSpring service.
	* Distribution of the SDK binaries, in their original or modified form, is only allowed in conjunction with your own software that integrates with LicenseSpring.
	* Distributed versions, including derivative works, may not be:
		* Provided as part of a hosted or cloud-based service that allows others to access the SDK’s functionality without interacting directly with the LicenseSpring service.
		* Integrated into other services that compete with or do not use the LicenseSpring service.

3. Usage Restrictions:

	* The SDK binaries, in their original or modified form, may only be used as part of the LicenseSpring service.
	* You are prohibited from using the SDK binaries independently or as part of any service that does not interact with the LicenseSpring service.

4. Prohibited Actions:
	
	* You may not reverse engineer, decompile, or disassemble the SDK binaries, except as expressly permitted by applicable law.
	* You must not modify, remove, or obscure any license notices, copyright notices, or other proprietary notices from the SDK binaries without permission from Cense Data Inc.

5. Contributions and Feedback:
	
	* By submitting suggestions, improvement ideas, feature requests, or any other feedback ("Contributions"), you grant LicenseSpring a perpetual, worldwide, royalty-free, irrevocable license to use, reproduce, modify, distribute, and incorporate the Contributions into the SDK or any other products or services of LicenseSpring.
	* LicenseSpring retains sole ownership and rights to the SDK binaries and any incorporated Contributions.

6. Termination:
	* Any violation of these terms will result in the automatic termination of your rights under this license.
	* Upon termination, you must cease all use and distribution of the SDK binaries and destroy all copies in your possession.

7. Disclaimer of Warranty and Liability:

	* Permission to use, copy, and/or distribute the SDK binaries for any purpose with or without fee is hereby granted under the conditions outlined above.

	THE SOFTWARE IS PROVIDED "AS IS" AND LICENSESPRING DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. LICENSESPRING SHALL NOT BE LIABLE FOR ANY DAMAGES ARISING OUT OF OR RELATED TO THE USE OR PERFORMANCE OF THE SOFTWARE.

Copyright 2025 Cense Data Inc DBA LicenseSpring
Contact: support@licensespring.com
```

## Dependencies

Note that these libraries also make use of other open source libraries - those are not listed here.

### SLF4J

The Simple Logging Façade for Java (SLF4J) acts as a straightforward façade or abstraction layer for diverse logging frameworks (such as java.util.logging, logback, log4j). This empowers users to integrate their preferred logging framework during deployment. This integration permits end users to tailor the SDK's logging to their specific requirements.

### Feign

We employ Netflix's OpenFeign library to interact with the remote HTTP server. Additionally, we utilize the bundled OkHttp3 client, included with the OpenFeign library, contributing to cleaner and more organized code.

### Gson

Utilizing Google's JSON serializer, the Java SDK maintains uniform naming within Java classes while adhering to the server-side snake-case JSON convention. This approach ensures efficient data compatibility between the SDK and server components.

### BouncyCastle

Bouncy Castle, an open-source cryptography library, plays a pivotal role in ensuring secure communication with LicenseSpring servers. This involves comprehensive utilization for generating and verifying signatures, contributing to a secure and reliable data exchange.

### OSHI

OSHI, which stands for Operating System and Hardware Information, is a versatile cross-platform library employed for acquiring essential system information. With OSHI, you can retrieve comprehensive data regarding operating systems and hardware components, enhancing your understanding of system configurations.

### Lombok

Lombok is a convenient library designed to eliminate repetitive boilerplate code in Java. It generates getters, setters, and the builder pattern, simplifying the creation of value objects (immutable structures). By offering a neat and intuitive interface for API interaction, Lombok enhances the SDK user experience. It's important to note that the library dependency isn't included in the final output binaries.

Versions currently being used in latest SDK:

```xml
<gson.version>2.11.0</gson.version>
<slf4j.version>1.7.30</slf4j.version>
<lombok.version>1.18.20</lombok.version>
<feign.version>13.1</feign.version>
<bouncycastle>1.78</bouncycastle>
<oshi-version>6.6.0</oshi-version>
```

## Dependency Licenses

Aggregated Licenses from open source dependencies present within the LicenseSpring Java SDKS. Please note that any dependency that contains the GPL/LGPL license, also has an Apache 2.0 license attached, so the GPL/LGP licenses can be ignored.

They are also included in the .jar under `/META-INF/DEPENDENCIES_LICENSES.txt`

::File[]{src="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/B9AMhDmzi1NQkP9QIHl6j_licenses-2170.zip" signedSrc="https://archbee-doc-uploads.s3.us-east-1.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/B9AMhDmzi1NQkP9QIHl6j_licenses-2170.zip?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAYQNQCIXNIQWBC56C%2F20250212%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250212T163023Z&X-Amz-Expires=86400&X-Amz-Signature=95ecfa15a26941b1113589e659fa95c32733a21f93f164e0d3448adf79f50f25&X-Amz-SignedHeaders=host&x-id=GetObject" label="licenses_2.17.0.zip" isUploading="false"}

```xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<licenseSummary>
  <dependencies>
    <dependency>
      <groupId>com.github.oshi</groupId>
      <artifactId>oshi-core</artifactId>
      <version>6.6.0</version>
      <licenses>
        <license>
          <name>SPDX-License-Identifier: MIT</name>
          <url>https://opensource.org/licenses/MIT</url>
          <distribution>repo</distribution>
          <file>spdx-license-identifier: mit - mit.html</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.11.0</version>
      <licenses>
        <license>
          <name>Apache-2.0</name>
          <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <file>apache-2.0 - license-2.0.txt</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>com.google.errorprone</groupId>
      <artifactId>error_prone_annotations</artifactId>
      <version>2.27.0</version>
      <licenses>
        <license>
          <name>Apache 2.0</name>
          <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <file>apache 2.0 - license-2.0.txt</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>com.squareup.okhttp3</groupId>
      <artifactId>okhttp</artifactId>
      <version>4.12.0</version>
      <licenses>
        <license>
          <name>The Apache Software License, Version 2.0</name>
          <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <file>apache 2.0 - license-2.0.txt</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>com.squareup.okio</groupId>
      <artifactId>okio-jvm</artifactId>
      <version>3.6.0</version>
      <licenses>
        <license>
          <name>The Apache Software License, Version 2.0</name>
          <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <distribution>repo</distribution>
          <file>apache 2.0 - license-2.0.txt</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>com.squareup.okio</groupId>
      <artifactId>okio</artifactId>
      <version>3.6.0</version>
      <licenses>
        <license>
          <name>The Apache Software License, Version 2.0</name>
          <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <distribution>repo</distribution>
          <file>apache 2.0 - license-2.0.txt</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>io.github.openfeign</groupId>
      <artifactId>feign-core</artifactId>
      <version>13.1</version>
      <licenses>
        <license>
          <name>The Apache Software License, Version 2.0</name>
          <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <distribution>repo</distribution>
          <file>apache 2.0 - license-2.0.txt</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>io.github.openfeign</groupId>
      <artifactId>feign-gson</artifactId>
      <version>13.1</version>
      <licenses>
        <license>
          <name>The Apache Software License, Version 2.0</name>
          <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <distribution>repo</distribution>
          <file>apache 2.0 - license-2.0.txt</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>io.github.openfeign</groupId>
      <artifactId>feign-okhttp</artifactId>
      <version>13.1</version>
      <licenses>
        <license>
          <name>The Apache Software License, Version 2.0</name>
          <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <distribution>repo</distribution>
          <file>apache 2.0 - license-2.0.txt</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>io.github.openfeign</groupId>
      <artifactId>feign-slf4j</artifactId>
      <version>13.1</version>
      <licenses>
        <license>
          <name>The Apache Software License, Version 2.0</name>
          <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <distribution>repo</distribution>
          <file>apache 2.0 - license-2.0.txt</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>net.java.dev.jna</groupId>
      <artifactId>jna-platform</artifactId>
      <version>5.14.0</version>
      <licenses>
        <license>
          <name>LGPL-2.1-or-later</name>
          <url>https://www.gnu.org/licenses/old-licenses/lgpl-2.1</url>
          <distribution>repo</distribution>
          <comments>Java Native Access (JNA) is licensed under the LGPL, version 2.1 or
        later, or the Apache License, version 2.0. You can freely decide which
        license you want to apply to the project.</comments>
        </license>
        <license>
          <name>Apache-2.0</name>
          <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <distribution>repo</distribution>
          <file>apache-2.0 - license-2.0.txt</file>
          <comments>Java Native Access (JNA) is licensed under the LGPL, version 2.1 or
        later, or the Apache License, version 2.0. You can freely decide which
        license you want to apply to the project.</comments>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>net.java.dev.jna</groupId>
      <artifactId>jna</artifactId>
      <version>5.14.0</version>
      <licenses>
        <license>
          <name>LGPL-2.1-or-later</name>
          <url>https://www.gnu.org/licenses/old-licenses/lgpl-2.1</url>
          <distribution>repo</distribution>
          <comments>Java Native Access (JNA) is licensed under the LGPL, version 2.1 or
        later, or the Apache License, version 2.0. You can freely decide which
        license you want to apply to the project.</comments>
        </license>
        <license>
          <name>Apache-2.0</name>
          <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <distribution>repo</distribution>
          <file>apache-2.0 - license-2.0.txt</file>
          <comments>Java Native Access (JNA) is licensed under the LGPL, version 2.1 or
        later, or the Apache License, version 2.0. You can freely decide which
        license you want to apply to the project.</comments>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>org.bouncycastle</groupId>
      <artifactId>bcpkix-jdk18on</artifactId>
      <version>1.78</version>
      <licenses>
        <license>
          <name>Bouncy Castle Licence</name>
          <url>https://www.bouncycastle.org/licence.html</url>
          <distribution>repo</distribution>
          <file>bouncy castle licence - licence.html</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>org.bouncycastle</groupId>
      <artifactId>bcprov-jdk18on</artifactId>
      <version>1.78</version>
      <licenses>
        <license>
          <name>Bouncy Castle Licence</name>
          <url>https://www.bouncycastle.org/licence.html</url>
          <distribution>repo</distribution>
          <file>bouncy castle licence - licence.html</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>org.bouncycastle</groupId>
      <artifactId>bcutil-jdk18on</artifactId>
      <version>1.78</version>
      <licenses>
        <license>
          <name>Bouncy Castle Licence</name>
          <url>https://www.bouncycastle.org/licence.html</url>
          <distribution>repo</distribution>
          <file>bouncy castle licence - licence.html</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-stdlib-common</artifactId>
      <version>1.9.10</version>
      <licenses>
        <license>
          <name>The Apache License, Version 2.0</name>
          <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <file>apache 2.0 - license-2.0.txt</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-stdlib-jdk7</artifactId>
      <version>1.8.21</version>
      <licenses>
        <license>
          <name>The Apache License, Version 2.0</name>
          <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <file>apache 2.0 - license-2.0.txt</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-stdlib-jdk8</artifactId>
      <version>1.8.21</version>
      <licenses>
        <license>
          <name>The Apache License, Version 2.0</name>
          <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <file>apache 2.0 - license-2.0.txt</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-stdlib</artifactId>
      <version>1.8.21</version>
      <licenses>
        <license>
          <name>The Apache License, Version 2.0</name>
          <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <file>apache 2.0 - license-2.0.txt</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>org.jetbrains</groupId>
      <artifactId>annotations</artifactId>
      <version>13.0</version>
      <licenses>
        <license>
          <name>The Apache Software License, Version 2.0</name>
          <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
          <distribution>repo</distribution>
          <file>apache 2.0 - license-2.0.txt</file>
          <comments>A business-friendly OSS license</comments>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.20</version>
      <licenses>
        <license>
          <name>The MIT License</name>
          <url>https://projectlombok.org/LICENSE</url>
          <distribution>repo</distribution>
          <file>the mit license - license.txt</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>2.0.7</version>
      <licenses>
        <license>
          <name>MIT License</name>
          <url>http://www.opensource.org/licenses/mit-license.php</url>
          <distribution>repo</distribution>
          <file>mit license - mit-license.html</file>
        </license>
      </licenses>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>2.0.9</version>
      <licenses>
        <license>
          <name>MIT License</name>
          <url>http://www.opensource.org/licenses/mit-license.php</url>
          <distribution>repo</distribution>
          <file>mit license - mit-license.html</file>
        </license>
      </licenses>
    </dependency>
  </dependencies>
</licenseSummary>

```


[title] /device-variables/
[path] Management API/Device/


[title] Getting Started
[path] SDKs/Tutorials/

LicenseSpring SDKs offer a comprehensive set of tools and libraries that empower you to create robust software licensing and entitlement systems with ease.&#x20;

Our SDKs are available in various programming languages, making it convenient to integrate LicenseSpring into your applications, irrespective of your development stack.

By utilizing LicenseSpring SDKs, you can:

- **Protect your software** from unauthorized use and distribution.
- Issue licenses with **flexible configurations**, catering to various licensing models.
- Implement **online and offline activation** mechanisms to accommodate different user scenarios.
- Validate licenses to ensure **compliance** and access to premium features.
- Deactivate licenses when necessary, providing better **control** over software distribution.

Whether you are an independent developer, a software vendor, or part of an enterprise team, LicenseSpring SDKs offer a seamless solution to manage and protect your software intellectual property.

Let's begin the journey by installing the LicenseSpring SDK and preparing it for use in your applications.

[title] Java License Client
[path] SDKs/Java SDK/Java Modules/

License Client is the basic module in LicenseSpring implementation. For most use cases it's the only module required for a successful LicenseSpring implementation.

To include License Client to your Maven/Gradle project use this snippet:

:::CodeblockTabs
```xml
     <dependencies>
       <dependency>
            <groupId>com.licensespring</groupId>
            <artifactId>licensespring-license-client</artifactId>
            <version>2.16.1</version>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>jdk-java</id>
            <url>https://licensespring-maven.s3.eu-central-1.amazonaws.com/</url>
        </repository>
    </repositories>
```

```java
repositories {
    mavenLocal()
    maven {
        url = 'https://licensespring-maven.s3.eu-central-1.amazonaws.com/'
    }
}

dependencies {
    implementation 'com.licensespring:licensespring-license-client:2.16.1'
}
```
:::

*Javadoc, Jar and OSGi bundle downloads can be found*[**Javadoc & Downloads**](docId\:Dm-Ksn9S-VVHGLpYWSm5x)

## Initializing the License Client

All of the methods are accessed via the `LicenseManager` singleton. This means you initialize the SDK once and then use it throughout your application. Once initialized, the SDK contacts the LicenseSpring server to check for an existing license for the current computer/product combination. If a valid license is found, it becomes immediately available as a License object.

To initialize the SDK, you must supply authentication credentials and product information. You can choose one of two authentication methods:

**1. API Key Authentication:**

- **apiKey:** Your company API key
- **sharedKey:** A company-specific encryption key used when signing requests

**2. OAuth Authorization:**

- **clientId:** Your client identifier
- **clientSecret:** Your client secret

In addition to the authentication credentials, you must provide the **productCode**, an alphanumeric code identifying the specific product. The `apiKey` and `sharedKey` are available in the LicenseSpring Platform under "Settings -> Settings -> Keys." For [**OAuth Authorization**](docId\:xhYZAUaL9QY4jerxKilmk), your `clientId` and `clientSecret` are available here: [**OAuth Configuration**](docId\:q1YECed3KGhZMwcSX2MOJ) . The `productCode` is defined when creating the product and ties the license to that specific product.

**Optional** Configuration parameters for initializing the License Client SDK:

- `licenseFilePath` determines where the license file will be stored on user's computer. By default, it is set to current working directory of the application with the filename `license.key`
- `offlineMode` enables offline mode. In this mode no requests are sent to LicenseSpring servers. Default is false.
- `enablePeriodicCheck` indicates if the Consumption APIs should be invoked periodically. Use with `Consumption` type licenses - when caching license state is required.
- `checkPeriod` period of invocation of the `checkLicense`  method. Defaults to 1 hour if `Duration` object is not provided. Enabled by the `enablePeriodicCheck` flag.
- `requestLogging` request logging for debug purposes, default is no request logging.
- `appName` name of the application using the SDK.
- `appVersion` manually set the version of the application that's using the SDK.
- `identityProvider` set a custom `IdentityProvider` which generates unique keys for a particular device. Default implementation is based on Motherboard/CPU/Disk. See [**Java Hardware (Device) IDs**](docId\:KinnDEO4BgHcV3azYvchM) for more information.
- `cacheHardwareId` set to true to allow caching of hardware IDs. Default is false
- `gracePeriodDays` period of days in which user can check `License` locally if API license check fails, this can either be a connection error or internal server error. Maximum of 30 days.
- `ignoreServerExceptions `similar to `gracePeriodDays`, SDK will check `License` locally if API license check fails, but with no time limit
- `enableNegativeConsumptions` enables the option to send negative consumptions, default is false.
- `proxyPort` and `proxyHost` used to setup a forward proxy, see more in [**Java Advanced Usage**](docId\:mqLRngvkrEpJ5IVdGUpt0).
- `requestTimeout` set the timeout of requests make to API (in seconds), default is 10 seconds
- `storeMachineInfo` - false by default. This toggles the collection of additional machine data, which includes:
  - `hostname`
  - `ipAddress`
  - `macAddress`
  - `vmInfo`
  - `osInfo`
- `infoToStore` - specify what information to store, ignored if `storeMachineInfo` is false, defaults to ALL if left empty.
- `airGappedPublicKey` - public key generated in the platform for air-gapped `Licences`

```java
// configuration with only required parameters
// NOTE building a LicenseSpringConfiguration without required parameters will throw a LicenseSpringConfigurationException
LicenseSpringConfiguration configuration = LicenseSpringConfiguration.builder()
                        .apiKey("api_key")
                        .sharedKey("shared_key")
                        .productCode("product_code")
                        .build();
                        
// OAuth minimum parameters
LicenseSpringConfiguration configuration = LicenseSpringConfiguration.builder()
                        .clientId("client_id")
                        .clientSecret("client_secret")
                        .productCode("product_code")
                        .build();                       

// configuration with more parameters
LicenseSpringConfiguration configuration = LicenseSpringConfiguration.builder()
                .apiKey("api_key")
                .productCode("product_code")
                .sharedKey("shared-key")
                .licenseFilePath("custom/path")
                .enablePeriodicCheck(true)
                .checkPeriod(Duration.ofHours(3))
                .requestLogging(Logger.Level.FULL)
                .appName("MyApplication")
                .appVersion("1.1.0")
                .cacheHardwareID(true)
                .gracePeriodDays(3)
                .enableNegativeConsumptions(true)
                .requestTimeout(60L)
                .storeMachineInfo(true)
                .infoToStore(InfoToStore.IP_ADDRESS)
                .build();

```

## LicenseManager

After setting up the SDK, there are a number of methods and objects available to the app developer. `LicenseManager` is a singleton that needs to be initialized once per runtime but can be retrieved using the `getInstance` method unlimited number of times.

```java
LicenseManager licenseManager = LicenseManager.getInstance();

// initialize the manager once per runtime with the configuration
// from the example above as a parameter

try {
	licenseManager.initialize(configuration);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

// or

try {
	if (!licenseManager.isInitialized()) {
  	   licenseManager.initialize(configuration);
    }

} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

```

## getCurrent()

In case no active license is available from the `LicenseRepository`, the return value will be null.

```java
License currentLicense = licenseManager.getCurrent();

if (currentLicense == null) {
  	// this means there are no active licenses on this device
	// actions taken in this if block depend on your needs
  	// you can provide the user a new license (if user is a new user)
  	// you can reactivate the license
  	// you can prompt the user to pay to get a new license (if for example, his subscription ended and his previous license expired)
  	// if the user is a first time user of your product you might wanna provide him a trial license if your product has a trial period
  	// to figure out what you want to do here see other methods from the LicenseManager that are at your disposal and you might get a grasp of what your use case would be
  
} else {
  	// this means there is an active license for your product on the device
  	// you can continue with your application flow
}

```

## getTrialLicense(String email)

You can generate a trial key directly from the app using the SDK, which will automatically associate this license key with the provided email. You can later use this data from the LicenseSpring platform to send out email campaigns targeting trial users for example.

:::hint{type="info"}
After you generate a trial key - the `UnactivatedTrialLicense` object will be returned, you still need to activate it using a call to `licenseManager.activateLicense()`
:::

```java
try {
    UnactivatedTrialLicense trial = licenseManager.getTrialLicense("someemail@gmail.com");
    License license = licenseManager.activateLicense(trial.createIdentity());
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
    return;
}

// if there weren't any exceptions 
// the LicenseManager will save the license 
// locally on the device using the LicenseRepository save() method
```

## getTrialLicense(Customer customer)

You can generate a trial key directly from the app using the SDK, which will automatically associate this license key with the provided customer. `Customer` object can be built using the builder, only email is required.

```java
// customer with only required field
Customer customer = Customer.builder()
        .email("someemail@gmail.com")
        .build();

// more verbose customer object
Customer customer = Customer.builder()
        .firstName("John")
        .lastName("Doe")
        .companyName("Company")
        .email("someemail@gmail.com")
        .phone("000-111-000")
        .reference("reference1212")
        .build();

try {
    UnactivatedTrialLicense trial = licenseManager.getTrialLicense(customer);
    License license = licenseManager.activateLicense(trial.createIdentity());
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
    return;
}
```

## activateLicense(ActivationLicense identity)

Attempts to activate the product using provided `ActivationIdentity`. Returns the `License` object that has been activated.

```java
// keybased
ActivationLicense keyBased = ActivationLicense.fromKey("license-key");
try {
	License activated = licenseManager.activateLicense(keyBased);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

// OR username/pass based - Note that this is the only API which requires the password.
// LicenseSpring will never store user passwords via the SDK.
ActivationLicense userBased = ActivationLicense.fromUsername("username", "password");

try {
	License activated = licenseManager.activateLicense(userBased);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}
```

## deactivateLicense(LicenseIdentity identity)

`License` is deactivated using a method on the `LicenseManager`. You need to supply the current license identity.

```java
// key based
try {
	boolean isDeactivated = licenseManager.deactivateLicense(LicenseIdentity.fromKey("sample-key"));
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

// user based
try {
	boolean isDeactivated = licenseManager.deactivateLicense(ActivationLicense.fromUsername("username", "password"));
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}
```

## checkLicense(License license)

Checks the license on the LS servers and syncs any consumptions made.

```java
try {
  	License updatedLicense = licenseManager.checkLicense(licenseManager.getCurrent());
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

```

## getInstallationFile(LicenseIdentity identity)

Returns the latest valid installation file, if installation files are defined in the LicenseSpring platform. For more details please see [**Product Versioning**](docId\:sz5ImOvmj5QJaWhELsOXt).&#x20;

```java
// key based
try {
	InstallationFile installationFile = licenseManager.getInstallationFile(LicenseIdentity.fromKey("sample-key"));
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}


// user based
try {
	InstallationFile installationFile = licenseManager.getInstallationFile(ActivationLicense.fromUsername("username", "password"));
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

```

## getVersions(LicenseIdentity identity)

Returns all the available versions for the product configured via configuration settings.

```java
try {
	String[] versions = licenseManager.getVersions(LicenseIdentity.fromKey("sample-key"));
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

```

## trackVariables(LicenseIdentity identity, Map\<String, String> variables)

Tracks device based variables for end uses. Can use the Variable builder as a utility.

```java
tr// KEY BASED
// build your own Map
try {
	licenseManager.trackVariables(LicenseIdentity.fromKey("sample-key"), new HashMap<>());
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

// use utility class to add some variables and track them
DeviceVariables deviceVars = DeviceVariables.builder()
     	.variable("one", "some value")
    	.variable("another_var", "other_value")
    	.build();

try {
	licenseManager.trackVariables(LicenseIdentity.fromKey("sample-key"), deviceVars.getVariables());
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}


// USER BASED
// build your own Map
try {
	licenseManager.trackVariables(ActivationLicense.fromUsername("username", "password"), new HashMap<>());
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

// use utility class to add some variables and track them
DeviceVariables deviceVars = DeviceVariables.builder()
        .variable("one", "some value")
        .variable("another_var", "other_value")
        .build();

try {
	licenseManager.trackVariables(ActivationLicense.fromUsername("username", "password"), deviceVars.getVariables());
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

```

## getProductDetails()

Gets product details from LicenseSpring servers.

```shell
try {
    Product product = licenseManager.getProductDetails();

    log.info(product.getProductName());
    log.info(product.getShortCode());
    log.info(product.isAllowTrial());
    log.info(product.getTrialDays());
    log.info(product.getAuthorizationMethod());
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

```

## offlineActivationFile(LicenseIdentity identity, String destination)

Generates an offline activation file which can be uploaded to LicenseSpring platform and activate the license. Default location for saving the file is Desktop, or if it can't be found, user home, this only applies if destination string is null. Default name of the file is "ls\_activation.req". For more information, see [**Offline License Activation**](docId\:FEyF5UIc8A7RvjQ9LCz3g).

```java
tr// KEY BASED
// build your own Map
try {
	licenseManager.trackVariables(LicenseIdentity.fromKey("sample-key"), new HashMap<>());
// key based with default file location 
try {
	licenseManager.offlineActivationFile(LicenseIdentity.fromKey("key"), null);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

// key based with custom file path
try {
	licenseManager.offlineActivationFile(LicenseIdentity.fromKey("key"), "/home/user/Downloads/offline/");
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

// user based with default file location 
try {
	licenseManager.offlineActivationFile(ActivationLicense.fromUsername("username", "password"), null);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

// user based with custom file path
try {
	licenseManager.offlineActivationFile(ActivationLicense.fromUsername("username", "password"), "/home/user/Downloads/offline/");
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}
```

## offlineDeactivationFile(LicenseIdentity identity, String destination)

Generates an offline deactivation file which can be uploaded to LicenseSpring platform and deactivate the license. Default location for saving the file is `Desktop`, or if it can't be found, user home, this only applies if destination string is null. Default file name is `ls_deactivation.req`.

```java
// key based with default file location 
try {
	licenseManager.offlineDeactivationFile(LicenseIdentity.fromKey("key"), null);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

// key based with custom file path
try {
	licenseManager.offlineDeactivationFile(LicenseIdentity.fromKey("key"), "/home/user/Downloads/deactivate/");
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}


// user based with default file location 
try {
	licenseManager.offlineDeactivationFile(ActivationLicense.fromUsername("username", "password"), null);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

// user based with custom file path
try {
	licenseManager.offlineDeactivationFile(ActivationLicense.fromUsername("username", "password"), "/home/user/Downloads/deactivate/");
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
```

## activateOfflineResponse(LicenseIdentity identity, String filePath)

Activates the license from a file that was generated on the LicenseSpring platform. If the `filePath` is null, SDK will look for the file `ls_activation.lic` in `Desktop`, or in user home.

```java
// key based with default file location 
try {
	License license = licenseManager.activateOfflineResponse(LicenseIdentity.fromKey("key"), null);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

// key based with custom file path
try {
	License license = licenseManager.activateOfflineResponse(LicenseIdentity.fromKey("key"), "/home/user/Downloads/");
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}


// user based with default file location 
License license = licenseManager.activateOfflineResponse(ActivationLicense.fromUsername("username", "password"), null);
try {

} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

// user based with custom file path
License license = licenseManager.activateOfflineResponse(ActivationLicense.fromUsername("username", "password"), "/home/user/Downloads/");
try {

} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}
```

## clearLocalStorage()

Clears all local license data.

```shell
try {
	licenseManager.clearLocalStorage();
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}
```

## setOfflineMode(boolean offlineMode)

Changes the offline mode while the app is running. While offline, no requests to LS servers are made.

```java
try {
	licenseManager.setOfflineMode(true);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}
```

## getAirGapActivationCode

Gets the activation code use for air gapped license

Needs the `LicenseSpringConfiguration` field: `airGappedPublicKey` to work with Air Gap Licences

```java
AirGappedActivation activation = licenseManager.getAirGapActivationCode(
	LicenseIdentity.fromKey("sample-key"), "initializationCodeFromPlatform"
);

log.info(activation.getActivationCode());
log.info(activation.getHardwareId());
log.info(activation.getLicenseKey());
```

## verifyAirGapConfirmationCode

Verifies the confirmation code for air gapped license

Needs the `LicenseSpringConfiguration` field: `airGappedPublicKey` to work with Air Gap Licences

```java
boolean verified = licenseManager.verifyAirGapConfirmationCode(
	LicenseIdentity.fromKey("sample-key"), 
  	"policyIdFromPlatform",
    "confirmationCodeFromPlatform"
);

log.info(verified);
```

## activateAirGapResponse

Activates the air gapped license from the license policy file

Needs the `LicenseSpringConfiguration` field: `airGappedPublicKey` to work with Air Gap Licences

```java
License license = licenseManager.activateAirGapResponse(
	LicenseIdentity.fromKey("sample-key"), 
  	"pathToPolicyFile",
    "policyId"
);

log.info(license.getHardwareId());
log.info(license.getIdentity().getLicenseKey());
```

## getAirGapDeactivationCode

Gets the deactivation code use for air gapped license

Needs the `LicenseSpringConfiguration` field: `airGappedPublicKey` to work with Air Gap Licences

```java
AirGappedDeactivation deactivation = licenseManager.getAirGapDeactivationCode(
	LicenseIdentity.fromKey("sample-key"), "initializationCodeFromPlatform"
);

log.info(deactivation.getDeactivationCode());
log.info(deactivation.getHardwareId());
log.info(deactivation.getLicenseKey());
```

## deactivateAirGapResponse

Deactivates the air gapped license from the license policy file and deleted the local license file

Needs the `LicenseSpringConfiguration` field: `airGappedPublicKey` to work with Air Gap Licences

```java
boolean deactivated = licenseManager.deactivateAirGapLicense(
	LicenseIdentity.fromKey("sample-key"), 
  	"pathToPolicyFile",
    "policyId"
);

assertTrue(deactivated);

License license = licenseManager.getCurrent();

assertNull(license);
```

## getSsoUrl

Gets the ssoUrl needed to activate the license using SSO - for more info, see [**Single Sign-On URL**](docId\:QbJwnphsDcS0L25UW6PTq)[**&#xA;**](https://app.archbee.com/docs/FbT_Z5Cu33D-LVZx1fRkU/QbJwnphsDcS0L25UW6PTq)*\* Note 1 - the activation code is short lived and converts into a user-based license after activation - DO NOT USE the ActivationLicense object used to activate the license, rather use the license.getIdentity after activation*
*\* Note 2 - the generated credentials are one-time use, generating new ones will disable previous*

```java
SSOUrl ssoURL = licenseManager.getSsoUrl(customerAccountCode, SSOResponseType.CODE);

//Follow the url to get the "code" or "id_token", this example is with "code"

String customerAccountCode = "yourCustomerAccountCodeWithSsoConfigured";
String code = "codeFromTheResponse";

//the ActivationLicense won't work after doing the activation
//use license.getIdentity() for usage in other methods after activation
ActivationLicense activationLicense = ActivationLicense.fromSsoCode(code, customerAccountCode);

License license = licenseManager.activateLicense(activationLicense);
License checkedLicense = licenseManager.checkLicense(license);
boolean deactivated = licenseManager.deactivateLicense(license.getIdentity());
```

## changeOauthClientSecret

Changes the OAuth Client Secret used for auth -> in case you have a rotating secret


```java
licenseManager.changeOAuthClientSecret("otherClientSecret");
```


[title] Swift SDK Installation
[path] SDKs/Tutorials/Getting Started/Swift / Objective-C/

The Swift LicenseSpring SDK can be downloaded at: [**Swift/Objective-C SDK**](docId\:aU3X3i1F0Z_yCq41LWhxh)

We provide Swift SDK as XCFramework that covers multiple platforms and architectures:

- macOS - ARM
- macOS - Intel
- iOS
- iOS Simulator - ARM
- iOS Simulator - Intel
- iOS + Catalyst - ARM
- iOS + Catalyst - Intel

Deployment targets:

- macOS 10.13
- iOS 12.0

## Installation

To use the SDK, just add LicenseSpring.xcframework to your project in Xcode.

Detailed approach can be found here: [**How to add XCFramework to your project**](https://www.simpleswiftguide.com/how-to-add-xcframework-to-xcode-project/)

[title] Advanced Usage
[path] SDKs/Tutorials/

Welcome to the Advanced Usage section of the LicenseSpring documentation!&#x20;

Here, we analyze the more intricate aspects of utilizing the LicenseSpring SDK to its fullest potential.&#x20;

While our basic integration guide provides a solid foundation, this section is designed to empower you with the expertise to harness the advanced features of licensing and entitlement management.

We understand that as your software evolves, **so do your requirements.**&#x20;

This section equips you with the tools to meet the challenges of a dynamic software landscape. &#x20;

[title] Management SDK Configuration and Usage
[path] SDKs/Tutorials/Getting Started/.NET/C# Management SDK/

This guide is designed to help you configure your application and start using LicenseSpring Management SDK functionality.

As you navigate through this tutorial, you'll acquire the knowledge to issue licenses and manage orders within your .NET application.

## Configuration

To initialize the SDK, you must fill in your LicenseSpring Management API key. It can be found on your LicenseSpring account under Settings->Keys:

![](https://lh6.googleusercontent.com/sjOHepSGSvoibbgDvQFp65NqS-69SWc2tsCYxX6cidCO6S0L4NkyIyNyfijVOlIEcd7TuciT2LHI-nHNr3BcnuoF1Szy8duHmaYfJ7UinCCZIrx3aiKaZAh4M_jHbzuIeBXEahui62Fa2Z6vN2dCeA)

:::hint{type="info"}
Note: API keys for licensing and management SDKs are different.
:::

Copy this value and create the configuration as shown below:

```csharp
var configuration = new LicenseSpring.ManagementConfiguration( ManagementAPIKey );
```

Now you can create **ManagementService** using this configuration object:

```csharp
var service = new ManagementService( configuration );
```

## Creating licenses

To create a key-based license you need to generate a license key:

```csharp
string productCode = "CODE";
var licenseKeys = service.LicenseService.GenerateLicenseKey( productCode );
```

Then create a **LicenseDetails** object and set the necessary values:

```csharp
var license1 = new LicenseDetails();
license1.LicenseKey = licenseKeys[0];
license1.EnableMaintenancePeriod = true;
license1.MaintenanceDuration = "3m";
```

Now you can create an order:

```csharp
var keyBasedOrderId = service.OrderService.CreateOrder( new[] { license1 }, productCode );
```

This method allows to specify order info such as customer:

```csharp
var customer = new Customer()
{
   CompanyName = "TestCompany",
   Email = "someone@test.com"
};
var orderInfo = new Order( customer );
var keyBasedOrderId = service.OrderService.CreateOrder( new[] { license1 }, productCode, orderInfo );
```

## Managing orders

Use the returned order id to get order information and manage the order. For example, get licenses from the order:

```csharp
ListOrdersRequestDto dto = new ListOrdersRequestDto()
{
   ClientOrderId = keyBasedOrderId 
};
uint count;
var ret = service.OrderService.ListOrders( dto, out count );
License[] licenses = null;
if( count == 1 && ret != null )
   licenses = service.OrderService.ListOrderLicenses( ret[0].Id );
```

You can also append licenses to an existing order:

```csharp
licenseKeys = service.LicenseService.GenerateLicenseKey( productCode );
var license2 = new LicenseDetails
{
   LicenseKey = licenseKeys[0],
   Type = LicenseType.Consumption,
   MaxConsumptions = 100,
   AllowOverages = true,
   MaxOverages = 50,
   ResetConsumption = true,
   ConsumptionPeriod = ConsumptionPeriod.Weekly
};
orderInfo = new Order( keyBasedOrderId, customer );
keyBasedOrderId = service.OrderService.CreateOrder(  new[] { license2 }, productCode, orderInfo );
```

:::hint{type="info"}
Note: one order cannot contain key-based and user-based licenses. It contains licenses for one product.
:::

## User-based licenses

The process of creating a user-based license is almost the same. However, you do not need to generate keys. Also, ensure that the specified product is user-based.

```csharp
string productCode = "UBCODE";
var license = new LicenseDetails
{
   EnableMaintenancePeriod = true,
   MaintenanceDuration = "7m", // 7 months
   Type = LicenseType.Consumption,
   MaxConsumptions = 10
};
var userBasedOrderId = service.OrderService.CreateOrder( new[] { license }, productCode );
```

To assign a user to the created license, retrieve the license using the order ID as shown above and assign the user by license ID:

```csharp
LicenseUser user = new LicenseUser()
{
   Email = "example@email.com",
   IsManager = false
};
service.LicenseService.AssignUser( license.Id, user );
```


[title] .NET SDK Installation
[path] SDKs/Tutorials/Getting Started/.NET/C#/

You may add the LicenseSpring .NET SDK to your project via NuGet or download the SDK here: [**.NET/C# SDK**](docId\:EE620oJMThwCyopGHOMfL)

The supported versions are:

- .NET: net5.0, net6.0, net7.0
- .NET Standard: netstandard2.0, netstandard2.1
- .NET Framework: 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8

## NuGet Package

[**https://www.nuget.org/packages/LicenseSpring.NetSDK**](https://www.nuget.org/packages/LicenseSpring.NetSDK)

:::CodeblockTabs
.NET CLI

```none
dotnet add package LicenseSpring.NetSDK --version 7.21.0
```

Package Manager

```tex
NuGet\Install-Package LicenseSpring.NetSDK -Version 7.21.0
```

PackageReference

```tex
<PackageReference Include="LicenseSpring.NetSDK" Version="7.21.0" />
```

Paket CLI

```tex
paket add LicenseSpring.NetSDK --version 7.21.0
```

```none
#r "nuget: LicenseSpring.NetSDK, 7.21.0"
```
:::

![NuGet Package Manager](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/hDK9zn1lVOdk-7Xx6sEQf_screenshotnuget.png "NuGet Package Manager")

## Package Content

![.NET Package Contents](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8JlkuDh56kGnSUOreFdUB_image.png ".NET Package Contents")

After downloading and unzipping the archive, you will find the following items in the **LicenseSpring&#x20;**&#x66;older:

**bin** folder:

- SDK: .NET versions 3.5; 4.0; 4.5; 4.5.1; 4.5.2; 4.6; 4.6.1; 4.6.2; 4.7; 4.7.1; 4.7.2; 4.8; 5.0; 6.0; 7.0; .NET Standard 2.0, .NET Standard 2.1, Xamarin.Forms

**documentation&#x20;**&#x66;older:

- A full reference of SDK classes through Doxygen.

**samples** folder:

- Code samples for multiple scenarios, including: air-gapped, console, NetCore, WinForm, VB.Net and VBA, cross-platform, Xamarin.Forms, single-sign-on, and web.

**Release notes** showing changelogs of all recent updates made to the SDK.


[title] .NET/C# Management SDK
[path] SDKs/

## ZIP File Includes:

- SDK: .NET versions 3.5; 4.0; 4.5; 4.5.1; 4.5.2; 4.6; 4.6.1; 4.6.2; 4.7; 4.7.1; 4.7.2; 4.8; .NET Standard 2.0, .NET Standard 2.1, .Net5, .Net6, .Net7, .Net8
- Code Samples for Console apps, ASP.Net app
- Documentation
- Release notes

[**LicenseSpringManagement.NetSDKv1.15.0.zip**](https://sdk.licensespring.com/.NET-Management-SDK/v1.15.0/LicenseSpringManagement.NetSDK-v1.15.0.zip)

## Release Notes

### November 18, 2025, v1.15.0

- Added `MaintenancePeriod` property to `ILicenseDetails`, `LicenseDetails`, and `UpdateLicenseRequestDto`.

### November 11, 2025, v1.14.2

- Fixed a bug where `LicenseDetails.MaxTransfers` type was uint instead of int, as value of -1 is used to prevent device transfers.

### October 7, 2025, v1.14.1

- Fixed an issue with exception handling when the server returns an invalid exception code, now the correct `LicenseSpringException` will be thrown.

### September 20, 2025, v1.14.0

- Enabled creating licenses with product features - please check `ManagementConsoleSample` project, `ManagementSample.CreateProductFeatures()` method.
- Added `ProductFeature(string code)` constructor to `ProductFeature`.
- Added setters to `ProductFeature` properties.

:::hint{type="info"}
Note: Product features with invalid codes are ignored by the API. If a non-existent feature code is provided, the license will be created without that feature.

Note 2: `ProductFeature` objects passed to the `LicenseDetails.ProductFeatures`array are decoupled, meaning you can't edit them once you pass them to the setter. If you need to update the values always create and pass a new array.
:::

### August 19, 2025, v1.13.0

- Added filters to `ListLicensesRequestDto`:&#x20;
  - `OrderCustomerAccount`
  - `OrderCustomerAccountName`
  - `OrderCustomerAccountNameContains`
  - `OrderCustomerAccountCode`
  - `OrderCustomerAccountCodeContains`

### July 17, 2025, v1.12.0

- Added `StartDate` property to `ILicense`.
- Added `CustomerAccountCode` filter to `ListLicensesRequestDto`.



### May 14, 2025, v1.11.0

- Added `Metadata` properties where applicable.
- Updated console sample.

### April 5, 2024, v1.10.1

- Fixed duplicate `custom_fields` members in `LicenseDetails`
- Updated console sample.

### March 7, 2024, v1.10.0

- Added `Note`property to `LicenseDetails.cs` and `Order.cs`.
- Updated console sample.

### March 5, 2024, v1.9.1&#xD;

- Fixed null reference exception in `Order` constructor.
- Fixed faulty exact email filter on customer.
- Expanded console sample.
- Added .NET 8 target build.

### July 4, 2023, v1.9.0&#xD;

- Added `CreateInstallationFileDto.Channel` and `CreateInstallationFileDto.Enabled` fields.
- Added .NET 6 and 7 target builds.

### April 14, 2023, v1.8.0&#xD;

- Added `ListCustomerAccounts`, `CreateCustomerAccount`, `EditCustomerAccount`, `DeleteCustomerAccount`, `MergeCustomers` functions to `CustomerService` class.
- Added `DeviceService.BorrowDevice` feature.
- Added `ListActivationHistories`, `ListUsageHistories` functions to `LicenseService` class.
- Added `OrderService.UpdateOrder` and `OrderService.RemoveManagerFromOrder` features.
- Fixed updating licenses issue.

### December 23, 2022, v1.7.0&#xD;

- Added `ConsumptionPeriod` class.
  Fixed issues in:
  - `CountLicenseTransfers` method,
  - `CustomerService` class,
  - `AddLabelToCustomer` method,
  - `UpdateCustomer` method.
- Implemented `LicenseService.DeleteLicense`, `LicenseService.CheckLicense`, `LicenseService.SetUserPassword` methods. Removed obsolete methods.
- Fixed issue in `LicenseService.SaveLicenseByKey` method.
- Added consumption-related fields to `ProductFeature` class.
- Added minor fixes to the `ManagementSample`.

### October 25, 2021, v1.6.0&#xD;

- Updated `ManagementConsoleSample` for creating key-based and user-based licenses, updating the licenses and assigning license users.
- Updated `UserBasedLicenseSample` for creating user-based license without users and assigning a license user.
- Created methods for:
  - Assigning managers to orders: `AddManagerToOrder`.
  - Countint license transfers: `CountLicenseTransfers`.
  - Creating and updating license custom fields: `CreateLicenseCustomField`, `UpdateLicenseCustomField`.
  - Listing and updating license users: `ListLicenseUsers`, `UpdateLicenseUser`.
  - Assigning and removing labels from customers: `AddLabelToCustomer`, `RemoveLabelFromCustomer`.
  - Retrieving, creating, updating and deleting customer labels: `ListCustomerLabels`, `CreateCustomerLabel`, `EditCustomerLabel`, `DeleteCustomerLabel`.

### October 7, 2021, v1.5.1&#xD;

- Fixed issues in `AssignUser` function. Created `UserBasedLicenseSample` demonstrating SDK usage for creating user-based licenses and assigning license users.

### October 4, 2021, v1.5.0

- Removed unused options from `ManagementConfiguration` and `ManagementExtendedOptions`. Removed unused classes and exceptions.&#x20;
- Updated Logger, added documentation to Dto classes.
- Created methods for:
  - Assigning users to licenses: `AssignUser`.
  - Unassigning users from licenses: `UnassignUser`.
  - Setting user passwords: `SetUserPassword`.

### August 31, 2021, v1.4.0

- Added new fields to the License class: `FloatingInUseDevices`, `LicenseUsers`, `OrderStoreId`, `ActiveUpToDateDevices`, `TotalActiveDevices`, `CreatedAt`, `UpdatedAt`, `TimeActivated`, `TimeDisabled`, `EnableMaintenancePeriod`, `SubscriptionId`, `LastCheck`, `PreventVm`, `ResetConsumption`, `ConsumptionPeriod`, `TrialDays`, `Note`, `MaxLicenseUsers`, `TransferCount`, `Order`, `OrderItem`, `DisabledUser`, `LastActivationDevice`.
- Updated samples `ManagementConsoleSample`, `UpdateLicenseOfflineSample`.

### August 2, 2021, v1.3.0

- Created methods for:
  - Resetting consumptions on licenses: `ResetConsumptions`.
  - Creating and deleting customers: `CreateCustomer`, `DeleteCustomer`.
  - Getting information about device variables: `ListDeviceVariables`.
  - Getting information about product installation files, features and custom fields: `ListInstallationFiles`, `ListProductFeatures`, `ListProductCustomFields`.
  - Creating, updating and deleting product custom fields: `CreateProductCustomField`, `UpdateProductCustomField`, `DeleteProductCustomField`.
  - Creating, updating and deleting product features: `CreateProductFeature`, `UpdateProductFeature`, `DeleteProductFeature`.
  - Creating, updating and deleting device variables: `CreateDeviceVariable`, `UpdateDeviceVariable`, `DeleteDeviceVariable`.
  - Creating installation files: `CreateInstallationFile`.
  - Deleting license custom fields: `DeleteLicenseCustomField`.

### July 22, 2021, v1.2.0

- Created methods for:
  - Resetting licenses: `ResetLicense`.
  - Resetting and blacklisting devices: `ResetDevice`, `BlacklistDevice`.
    Updated creation of files for offline license updating.
    Updated samples `ManagementConsoleSample`, `UpdateLicenseOfflineSample`.

### June 29, 2021, v1.1.0

- Created methods for:&#x20;
  - Updating license information: `UpdateLicense`, `UpdateLicenseProductFeatures`.
  - Enabling and disabling licenses: `EnableLicense`, `DisableLicense`, `DisableLicenseWithDevices`.
- Created `ASP.NetManagementSample` demonstrating SDK usage in ASP.Net applications

### May 20, 2021, v1.0.0

- Created methods for:
  - Retrieving and saving license information: `ListLicenses`, `ListLicenseCustomFields` `SaveLicenseByKey`;
  - Creating orders: `GenerateLicenseKey`, `CreateOrder`;
  - Getting information about orders: `ListOrders`, `ListOrderLicenses`, `ListManagersOnOrder`;
  - Getting information about devices: `ListDevices`;
  - Getting information about products: `ListProducts`;
  - Getting and editing information about customers: `ListCustomers`, `EditCustomer`.
    Created management SDK samples:
  - `ManagementConsoleSample` demonstrating usage of the SDK methods.
  - `UpdateLicenseOfflineSample` demonstrating creation of a file for updating license offline.


[title] List Hourly Activities Top Call Counts For Customers
[path] Management API/Analytics/Hourly Activities/

Show all hourly activities top call counts for customers the requesting manager has access permissions to.

**URL**: `/api/v1/activities-hourly/top_call_count_customers/`

**Method**: `GET`

### Query parameters:

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on customer account or related to the customer account.

Possible filters:

- `action__in`
  - values can be `consumption`, `f_consumption`, `check`, `activation`, `deactivation`, `activation_offline`, `deactivation_offline`, `trial_key`, `keygen`, `order`, `license_issued`, `change_password`, `customer_license_users`, `floating_release`, `installation_file`, `versions`, `product_details`, `get_device_variables`, `track_device_variables`, `ping`, `single_sign_on`, `floating_borrow`
- `product__in`
- `license__in`
- `status_code__in`
- `ts__*`
  - `*` can be `lte`, `gte`, `lt`, `gt`, `date__lte`, `date__gte`, `date__lt`, `date__gt`
- `status_code__*`
  - `*` can be `lte`, `gte`, `lt`, `gt`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "count": 30,
    "next": "http://127.0.0.1:5000/api/v1/activities-hourly/top_call_count_customers/?limit=20&offset=20",
    "previous": null,
    "results": [
        {
            "id": 1136,
            "email": "zaher.leon@gmail.com",
            "first_name": "Leon",
            "last_name": "Zaher",
            "company_name": "",
            "total_call_count": 17459
        },
        ...
    ]
}
```


[title] List Hourly Activities
[path] Management API/Analytics/Hourly Activities/

Show all hourly activities the requesting manager has access permissions to.

**URL**: `/api/v1/activities-hourly/`

**Method**: `GET`

### Query Parameters:

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on customer account or related to the customer account.

Possible filters:

- `action__in`
  - values can be `consumption`, `f_consumption`, `check`, `activation`, `deactivation`, `activation_offline`, `deactivation_offline`, `trial_key`, `keygen`, `order`, `license_issued`, `change_password`, `customer_license_users`, `floating_release`, `installation_file`, `versions`, `product_details`, `get_device_variables`, `track_device_variables`, `ping`, `single_sign_on`, `floating_borrow`
- `product__in`
- `license__in`
- `status_code__in`
- `ts__*`
  - `*` can be `lte`, `gte`, `lt`, `gt`, `date__lte`, `date__gte`, `date__lt`, `date__gt`
- `status_code__*`
  - `*` can be `lte`, `gte`, `lt`, `gt`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "count": 3626,
    "next": "http://127.0.0.1:5000/api/v1/activities-hourly/?limit=20&offset=20",
    "previous": null,
    "results": [
        {
            "id": 1394,
            "ts": "2021-04-07T15:00:00Z",
            "action": "activation",
            "count": 1,
            "call_count": 1,
            "extra": null,
            "status_code": 200,
            "company": 2,
            "product": 1534924343642079,
            "license": null
        },
        ...
    ]
}
```


[title] List Hourly Activities Total Call Counts
[path] Management API/Analytics/Hourly Activities/

Show all hourly activities total call counts the requesting manager has access permissions to.

**URL**: `/api/v1/activities-hourly/total_call_count/`

**Method**: `GET`

### Query Parameters:

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on customer account or related to the customer account.

Possible filters:

- `action__in`
  - values can be `consumption`, `f_consumption`, `check`, `check_feature`,  `activation`, `deactivation`, `activation_offline`, `deactivation_offline`, `trial_key`, `keygen`, `order`, `license_issued`, `change_password`, `customer_license_users`, `floating_release`, `installation_file`, `versions`, `product_details`, `get_device_variables`, `track_device_variables`, `ping`, `single_sign_on`, `floating_borrow`
- `product__in`
- `license__in`
- `status_code__in`
- `ts__*`
  - `*` can be `lte`, `gte`, `lt`, `gt`, `date__lte`, `date__gte`, `date__lt`, `date__gt`
- `status_code__*`
  - `*` can be `lte`, `gte`, `lt`, `gt`
- `time`
  - value can be `daily` to return results grouped by day instead of hour

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "count": 734,
    "next": "http://127.0.0.1:5000/api/v1/activities-hourly/total_call_count/?limit=20&offset=20",
    "previous": null,
    "results": [
        {
            "ts": "2021-04-06T18:00:00Z",
            "total_call_count": 7
        },
        ...
    ]
}
```


[title] List Hourly Activities Top Call Counts For Licenses
[path] Management API/Analytics/Hourly Activities/

Show all hourly activities top call counts for licenses the requesting manager has access permissions to.

**URL**: `/api/v1/activities-hourly/top_call_count_licenses/`

**Method**: `GET`

### Query Parameters:

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on customer account or related to the customer account.

Possible filters:

- `action__in`
  - values can be `consumption`, `f_consumption`, `check`, `activation`, `deactivation`, `activation_offline`, `deactivation_offline`, `trial_key`, `keygen`, `order`, `license_issued`, `change_password`, `customer_license_users`, `floating_release`, `installation_file`, `versions`, `product_details`, `get_device_variables`, `track_device_variables`, `ping`, `single_sign_on`, `floating_borrow`
- `product__in`
- `license__in`
- `status_code__in`
- `ts__*`
  - `*` can be `lte`, `gte`, `lt`, `gt`, `date__lte`, `date__gte`, `date__lt`, `date__gt`
- `status_code__*`
  - `*` can be `lte`, `gte`, `lt`, `gt`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "count": 231,
    "next": "http://127.0.0.1:5000/api/v1/activities-hourly/top_call_count_licenses/?limit=20&offset=20",
    "previous": null,
    "results": [
        {
            "id": 1620126830961029,
            "created_at": "2021-05-04T11:13:50Z",
            "key_or_users": "GEGY-YWXW-ZMAK-MKGP",
            "product": {
                "id": 1584723961091264,
                "product_name": "Great product"
            },
            "order": {
                "id": 1620126830959009
            },
            "total_call_count": 5439
        },
        ...
    ]
}
```


[title] Create Device Variable
[path] Management API/Device/Device Variables/

Creates a device variable, if requesting manager has access permissions to it.

**URL**: `/api/v1/device-variables/`

**Method**: `POST`

### Parameters:

- `device` - Integer
- `variable` - String
- `value` - String

### Data Example:

```json
{   "variable":"2",
    "value":"2",
    "device":90001
}
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 90007,
    "created_at": "2025-05-26T12:56:24.845640Z",
    "variable": "2",
    "value": "2",
    "device": 90001
}
```


[title] Retrieve Device Variable
[path] Management API/Device/Device Variables/

Retrieves a single device variable, if requesting manager has access permissions to it.

**URL**: `/api/v1/device-variables/{id}/`

**Method**: `GET`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 2013,
    "created_at": "2021-01-27T09:00:51Z",
    "variable": "v1",
    "value": "aaa",
    "device": 1112
}
```


[title] Whitelist Device
[path] Management API/Device/

Whitelist a single device if requesting manager has access permissions to it.

**URL**: `/api/v1/devices/{id}/whitelist/`

**Method**: `POST`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{"message": "Device whitelisted"}
```


[title] Blacklist Device
[path] Management API/Device/

Blacklist a single device if requesting manager has access permissions to it.

**URL**: `/api/v1/devices/{id}/blacklist/`

**Method**: `POST`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "message": "Device blacklisted."
}
```


[title] Borrow Device
[path] Management API/Device/

Borrow a single device if requesting manager has access permissions to it.

**URL**: `/api/v1/devices/{id}/borrow/`

**Method**: `POST`

### Parameters:

- `borrowed_until` - DateTime

### Data Example:

```json
{
    "borrowed_until": "2022-04-14T12:30:50"
}
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "device_id": 1124,
    "license_id": 1623736794797049,
    "borrowed_until": "2022-04-14T12:30:50Z",
    "max_borrow_time": 2
}
```


[title] Release Borrowed Device
[path] Management API/Device/

Release a single borrowed device if requesting manager has access permissions to it.

**URL**: `/api/v1/devices/{id}/borrow_release/`

**Method**: `POST`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "device_id": 1124,
    "license_id": 1623736794797049,
    "borrowed_until": null,
    "max_borrow_time": 2
}
```


[title] Reset Device
[path] Management API/Device/

Reset a single device if requesting manager has access permissions to it.

**URL**: `/api/v1/devices/{id}/reset/`

**Method**: `POST`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "message": "Device reset and license updated."
}
```


[title] Delete Device Variable
[path] Management API/Device/Device Variables/

Deletes a single device variable, if requesting manager has access permissions to it.

**URL**: `/api/v1/device-variables/{id}/`

**Method**: `DELETE`

### Success Response:

**Code**: `200 OK`

[title] Events list
[path] Events API/

## List of events

:::hint{type="info"}
This list will be expanded and new events will be added to it. End goal is to cover Create, Update and Delete events for all objects in LicenseSpring, and add some important action events ( eq. license.activated ).
:::

- **customer.deleted**
  - Publishers: platform
  - Consumers: webhooks, integrations
  - Data: customer
- **customer.updated**
  - Publishers: platform, license-api
  - Consumers: webhooks, integrations
  - Data: customer
- **device\_variable.created**
  - Publishers: platform, license-api
  - Consumers: webhooks
  - Data: device\_variable
- **device\_variable.deleted**
  - Publishers: platform
  - Consumers: webhooks
  - Data: device\_variable
- **device\_variable.updated**
  - Publishers: platform, license-api
  - Consumers: webhooks
  - Data: device\_variable
- **installation\_file.created**
  - Publishers: platform
  - Consumers: webhooks
  - Data: installation\_file
- **installation\_file.deleted**
  - Publishers: platform
  - Consumers: webhooks
  - Data: installation\_file
- **installation\_file.updated**
  - Publishers: platform
  - Consumers: webhooks
  - Data: installation\_file
- **license.activated**
  - Publishers: license-api
  - Consumers: webhooks
  - Data: license
- **license.created**
  - Publishers: license-api
  - Consumers: webhooks, integrations
  - Data: license
- **license.deactivated**
  - Publishers: license-api
  - Consumers: webhooks
  - Data: license
- **license.deleted**
  - Publishers: platform
  - Consumers: webhooks, integrations
  - Data: license
- **license.expired**
  - Publishers: platform
  - Consumers: webhooks
  - Data: license
- **license.license\_user.assigned**
  - Publishers: user-portal
  - Consumers: webhooks
  - Data: license, license\_user
- **license.license\_user.unassigned**
  - Publishers: user-portal
  - Consumers: webhooks
  - Data: license, license\_user
- **license.maintenance\_expired**
  - Publishers: platform
  - Consumers: webhooks
  - Data: license
- **license.maintenance\_will\_expire\_3\_days**
  - Publishers: platform
  - Consumers: webhooks
  - Data: license
- **license.reset**
  - Publishers: platform, user-portal
  - Consumers: webhooks
  - Data: license
- **license.updated**
  - Publishers: platform
  - Consumers: webhooks, integrations
  - Data: license
- **license.will\_expire\_3\_days**
  - Publishers: platform
  - Consumers: webhooks
  - Data: license
- **license.will\_expire\_3\_days**
  - Publishers: platform
  - Consumers: webhooks
  - Data: license
- **license\_custom\_field.created**
  - Publishers: platform
  - Consumers: webhooks
  - Data: license\_custom\_field
- **license\_custom\_field.deleted**
  - Publishers: platform
  - Consumers: webhooks
  - Data: license\_custom\_field
- **license\_custom\_field.updated**
  - Publishers: platform
  - Consumers: webhooks
  - Data: license\_custom\_field
- **license\_product\_feature.created**
  - Publishers: platform
  - Consumers: webhooks
  - Data: license\_product\_feature
- **license\_product\_feature.deleted**
  - Publishers: platform
  - Consumers: webhooks
  - Data: license\_product\_feature
- **license\_product\_feature.updated**
  - Publishers: platform
  - Consumers: webhooks
  - Data: license\_product\_feature
- **order.created**
  - Publishers: license-api
  - Consumers: webhooks
  - Data: order
- **order.deleted**
  - Publishers: platform
  - Consumers: webhooks
  - Data: order
- **order.license\_user.manager\_assigned**
  - Publishers: user-portal
  - Consumers: webhooks
  - Data: order, license\_user
- **order.updated**
  - Publishers: platform
  - Consumers: webhooks
  - Data: order
- **product.created**
  - Publishers: platform
  - Consumers: webhooks, integrations
  - Data: product
- **product.deleted**
  - Publishers: platform
  - Consumers: webhooks
  - Data: product
- **product.updated**
  - Publishers: platform
  - Consumers: webhooks, integrations
  - Data: product
- **product\_custom\_field.created**
  - Publishers: platform
  - Consumers: webhooks, integrations
  - Data: product\_custom\_field
- **product\_custom\_field.deleted**
  - Publishers: platform
  - Consumers: webhooks, integrations
  - Data: product\_custom\_field
- **product\_custom\_field.updated**
  - Publishers: platform
  - Consumers: webhooks, integrations
  - Data: product\_custom\_field
- **product\_feature.created**
  - Publishers: platform
  - Consumers: webhooks, integrations
  - Data: product\_feature
- **product\_feature.deleted**
  - Publishers: platform
  - Consumers: webhooks, integrations
  - Data: product\_feature
- **product\_feature.updated**
  - Publishers: platform
  - Consumers: webhooks, integrations
  - Data: product\_feature
- **license\_user\_group.created**
  - Publishers: platform
  - Consumers: webhooks
  - Data: license\_user\_group
- **license\_user\_group.updated**
  - Publishers: platform
  - Consumers: webhooks
  - Data: license\_user\_group
- **license\_user\_group.deleted**
  - Publishers: platform
  - Consumers: webhooks
  - Data: license\_user\_group
- **license\_user\_group.license\_user.manager\_assigned**
  - Publishers: platform, user-portal
  - Consumers: webhooks
  - Data: license\_user\_group, license\_user

## Global event data

Data sent with each event if applicable.

- id (str) - uuid4 generated unique event id
- event (str) - event code
- company\_id (int) - id of the company for which the event was triggered
- user\_id (int) - id of the user who triggered the event
- ts (int) - unix epoch timestamp of the event occurrence
- data (Object) - custom data depending on event

:::hint{type="warning"}
\`user\_id\` field is optional, and in some cases will be null.
:::

## Custom data

This section contains object data definitions for objects that are sent with each event. Which objects are sent with which event is defined in the List of events section above.

- **customer (Object)**
  - id (int)
  - email (str)
  - first\_name (str)
  - last\_name (str)
  - phone (str)
  - reference (str)
  - address (str)
  - postcode (str)
  - city (str)
  - country (str)
  - state (str)
- **license (Object)**
  - id (int)
  - activations\_type ( \`online\` | \`offline\` )
  - license\_key (str)
  - max\_license\_users (int)
  - is\_trial (boolean)
  - active (boolean)
  - validity\_period (date)
  - enable\_maintenance\_period (boolean)
  - maintenance\_period (date)
  - max\_activations (int)
  - times\_activated (int)
  - enabled (boolean)
  - total\_consumptions (int)
  - max\_consumptions (int)
  - order (Object)

- **license\_user (Object)**
  - id (int)
  - true\_email (str)
  - first\_name (str)
  - last\_name (str)

- **order (Object)**
  - id (int)
  - store\_id (str)
- **product (Object)**
  - id (int)
  - product\_name (str)
  - short\_code (str)
  - active (boolean)
  - authorization\_method (str)
  - is\_archived (boolean)
  - is\_bundle (boolean)


[title] Virtual Machine Detection
[path] SDKs/Tutorials/Best Practices/

Node-locking associates a software license with a specific device using a unique identifier, often derived from hardware IDs. This ensures that each license remains tied to one machine. &#x20;

In virtualized and containerized environments, hardware information reflects the virtual machine rather than the host device. This makes it more difficult to reliably bind licenses to the actual machine.&#x20;

LicenseSpring addresses this with specialized methods designed for containers and virtualization. These methods accurately detect virtual environments, enabling precise device identification and consistent license enforcement.&#x20;

This document describes LicenseSpring’s techniques for distinguishing virtual machine instances and explains how they strengthen software protection.&#x20;

## Prerequisites

1. Completed the [**Getting Started**](docId\:LSFY9tQ3vfq4ROOW9sHkd) Tutorial, specifically:
   - Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
   - Created a `LicenseID` using either `LicenseID::fromKey` or `LicenseID::fromUser` function, depending on the activation method you prefer.
   - Implemented basic license management, including license activations, deactivations, and both online and local license checks.

## Working With Virtual Machines

The LicenseSpring SDKs offer a distinctive feature: the capability to detect virtual machine environments.&#x20;

### Supported VMs

| VM name            | Java | C++SDK | .Net SDK | Swift SDK |
| ------------------ | ---- | ------ | -------- | --------- |
| Parallels Desktop  | -    | *      | -        | * [x] a   |
| QEMU               | -    | *      | -        | *         |
| VirtualBox         | -    | *      | -        | *         |
| Windows Virtual PC | -    | *      | -        | *         |
| VMware             | -    | *      | -        | *         |
| Wine               | -    | *      | -        | *         |
| Xen Project        | -    | *      | -        | *         |
| Docker             | -    | *      | -        | *         |
| Microsoft Hyper-V  | -    | *      | -        | *         |
| Microsoft Azure    | -    | *      | -        | *         |
| bhyve              | -    | *      | -        | *         |
| FreeBSD Jail       | -    | *      | -        | *         |
| KVM                | -    | *      | -        | *         |
| LXC                | -    | *      | -        | *         |
| Lguest             | -    | *      | -        | *         |
| Linux-VServer      | -    | *      | -        | *         |
| OpenVZ             | -    | *      | -        | *         |
| Project ACRN       | -    | *      | -        | *         |
| Virtual Iron       | -    | *      | -        | *         |
| QNX Hypervisor     | -    | *      | -        | *         |
| UTM                | -    | *      | -        | *         |

### Enabling Virtual Machine Detection

This functionality, designed to enhance software security, can be activated manually within your program through the SDK as shown below.

:::CodeblockTabs
```cpp
ExtendedOptions options;

options->enableVMDetection( true );

std::shared_ptr<Configuration> configuration = Configuration::Create(
     EncryptStr( "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" ), 
     EncryptStr( "XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX" ), 
     EncryptStr( "XXXXXX" ), 
     appName, appVersion, options );
```

```csharp
var options = new LicenseSpring.ExtendedOptions();
options.EnableVMDetection = true; 

var configuration = new LicenseSpring.Configuration(
            apiKey: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", 
            sharedKey: "XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX",
            productCode: "XXXXXX", 
            appName: "NAME",
            appVersion: "VERSION",
            extendedOptions: options );
```

```swift
let extendedOptions = ExtendedOptions(enableVMDetection: true)
let configuration = Configuration(
   apiKey: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", 
   sharedKey: "XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX",
   productCode: "XXXXXX", 
   extendedOptions: extendedOptions)
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x56;irtual machine detection is **disabled by default**. This feature must be enabled to make use of any features mentioned throughout this tutorial.
:::

:::hint{type="warning"}
We provide a **separate DLL** for VM detection in the **C++ SDK** package. Make sure you put this library with the LicenseSpring DLL. If it is not found, a **VMDNotAvailableException** will occur.
:::

### Detecting Whether Virtual Machine Detection is Enabled

After the configuration has been initialized, developers are able to detect whether virtual machine detection is currently activated with:

:::CodeblockTabs
```cpp
if ( configuration->isVMDetectionEnabled ) {
    //VM detection is enabled.
}
```

```csharp
if ( configuration.IsVMDetectionEnabled ) {
    //VM detection is enabled.
}
```

```swift
if (configuration.IsVMDetectionEnabled ) {
    //VM detection is enabled.
}
```
:::

Within the C++ SDK, this can also be checked through the `ExtendedOptions` object, as shown below:

```cpp
if ( options->isVMDetectionEnabled ) {
    //VM detection is enabled.
}
```

### Detecting Whether a User is on a Virtual Machine

The SDKs can also check for whether a specific user currently using the application is on a virtual machine by using:

:::CodeblockTabs
```cpp
if ( configuration->isVM() ) {
  //the user is currently running on a VM
}
```

```csharp
if ( configuration.IsVM ) {
  //the user is currently running on a VM
}       
```

```swift
if ( configuration.isVM ) {
  //the user is currently running on a VM
}
```
:::

### Retrieving Detected Virtual Machine Name

Developers can get the name of the user's hypervisor with the following:

:::CodeblockTabs
```cpp
vmName = configuration->getDetectedVMName()
```

```csharp
vmName = configuration.GetDetectedVMName()
```

```swift
let vmName = configuration.detectedVMName
```
:::

:::hint{type="danger"}
**VMDNotAvailableException (Windows only):** Thrown in the C++ and .NET SDK in the case that VM detection dll is not found, tempered or detection failed.
:::

## Preventing Virtual Machine Access

Licenses can also be restricted from activating on virtual machines through configuration settings. By selecting the **“prevent virtual machine”&#x20;**&#x6F;ption in the license settings, activation attempts within virtualized environments are blocked. This ensures that the software operates only on approved physical devices, in line with product requirements.&#x20;

![Prevent Virtual Machine](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/b09Vqr96cHaORTbHk0sT6_image.png "Prevent Virtual Machine")

When this feature is checked off, any actions involving our license, will result in an error/exception, making the license unusable on a VM.

Within the SDK, developers can check for whether a license is allowed to work under virtual machine or not with:

```cpp
if ( license->isVMAllowed ) {
    //VM detection is enabled.
}
```

:::hint{type="danger"}
**VMIsNotAllowedException:&#x20;**&#x54;hrown on virtual machine when VM detection is enabled but product policy prohibits running on VM.
:::


[title] Hardware ID generation
[path] SDKs/Tutorials/Best Practices/

A hardware ID is a unique device identifier used to bind a license to that device, which helps to avoid transferring licenses to other devices.

This tutorial will help you learn more about hardware ID algorithms provided by LicenseSpring SDKs and choose the optimal hardware ID algorithm for your application.

## Prerequisites

Completed the [**Getting Started**](docId\:LSFY9tQ3vfq4ROOW9sHkd) Tutorial, including:

1. Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
2. Activated a license of any type.
3. Implemented routine local and online checks within the application.&#x20;

## SDK-independent hardware ID generator library

We provide a SDK-independent hardware ID generator library as a dynamically-loadable shared library. This is a part of our on-going process to standardize licensing across all our SDKs. The library is integrated into:

- C++ SDK since v7.42.0,
- C# SDK since v7.34.0,
- Java SDK since v2.25.1,
- Go SDK since the v2 rewrite,
- Python SDK since v2.0.0,
- JavaScript SDK since initial release.

Swift and Android SDK use custom hardware ID generation algorithms as they are mostly tied to platforms with straightforward hardware ID generation.

Each SDK packages the shared library to be easily deployable either manually or through popular repositories and package managers. The library is released for multiple operating systems and architectures:

- For **Windows**, we provide binaries built for x64, x86 and ARM64 architectures, built with a VS2022 MSVC toolchain. We also provide a version built GCC 8.1 from Qt's distribution of MinGW.&#x20;
- For **macOS**, we provide binaries built for the x86\_64 architecture (min. required version 10.12) and arm64 architecture (min. required version 11.0).
- For **Linux**, we provide binaries built for i686, x86\_64, armv7l (i.e. armhf), ppc64le, s390x and riscv architectures, linked against either glibc 2.27 or musl libc.
- For **iOS**, we provide an XCFramework, which includes slices for `iphoneos` (arm64) and `iphonesimulator` (arm64 & x86\_64). The slices are shipped as static libraries, which means the framework must be statically linked into the consumer library or application.

### Algorithms list

The library exports an enum of available algorithms. Algorithm names in each SDK that FFIs into the library can easily be mapped to an algorithm in the following list:

```cpp
enum class HardwareIdAlgorithm {
    /**
     * @brief Default hardware ID calculation algorithm.
     *
     * @details Computes a default hardware identifier.
     * On Windows, computes HardwareIdAlgorithm::WindowsComputerSystemProductId.
     * On macOS, the algorithm uses `gethostuuid` to compute a unique machine
     * identifier.
     * On Linux, computes HardwareIdAlgorithm::LinuxMachineId.
     */
    Default,

    /**
     * @brief Alternative hardware ID algorithm for Windows.
     *
     * @details Computes a hardware fingerprint based on CPU, disk, and
     * motherboard.
     */
    WindowsHardwareFingerprintId,

    /**
     * @brief Default hardware ID algorithm for Windows.
     *
     * @details Gets the UUID of the Windows machine using the Computer System
     * Product UUID. See [Microsoft
     * Docs](https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-computersystemproduct).
     */
    WindowsComputerSystemProductId,

    /**
     * @brief Alternative hardware ID algorithm for Windows.
     *
     * @details Retrieves `SOFTWARE\Microsoft\Cryptography\MachineGUID` from
     * the Windows registry.
     */
    WindowsCryptographyId,

    /**
     * @brief Default hardware ID algorithm for Linux.
     *
     * @details Reads `/etc/machine-id` and `/var/lib/dbus/machine-id` in that
     * order. If these files don't exist, a new UUID is written to the
     * filesystem.
     */
    LinuxMachineId,

    /**
     * @brief Cloud platforms instance hardware ID algorithm.
     *
     * @details Retrieves the instance ID for cloud platforms, including Azure,
     * AWS, and GCP.
     */
    CloudPlatformsId
};
```

The full package can be downloaded on the [**hardware ID generator download page**](https://sdk.licensespring.com/#hardware_id_generator/).

### Configuration

When you have chosen the algorithm, set it to the **ExtendedOptions**.

:::CodeblockTabs
```cpp
LicenseSpring::ExtendedOptions options;

// DeviceIDAlgorithm::HardwareIdGeneratorDefault is the default 
// value for the new hardware ID generator library
options.setDeviceIdAlgorithm(HardwareIdGeneratorDefault);
```

```csharp
var options = new ExtendedOptions();
options.DeviceIdAlgorithm = DeviceIDAlgorithm.AutoId;
```

```swift
configuration.hardwareID = generateMyOwnCustomID()
```

```java
LicenseSpringConfiguration config = LicenseSpringConfiguration.builder()
  .identityProvider(HardwareIdStrategy.AUTO_HARDWARE_ID)
  .build();
```

```python
from licensespring.licensefile.config import Configuration
from licensespring.hardware import HardwareIdProviderSource

conf = Configuration(product="your_product_key",api_key="your_api_key",
                   shared_key="your_shared_key",file_key=key,file_iv=iv,
                   is_guard_file_enabled=True,hardware_id_provider=HardwareIdProviderSource
```
:::

SDKs also allow overriding the hardware ID. For instance, you can use the MAC address as the hardware ID:

:::CodeblockTabs
```cpp
LicenseSpring::ExtendedOptions options;
options.setHardwareID( options.getNetworkInfo().mac() );
```

```csharp
var configuration = new LicenseSpring.Configuration();
var options = new LicenseSpring.ExtendedOptions();
options.HardwareID = configuration.MACAddress;
configuration.ExtendedOptions = options;
```

```go
// Go SDK v2
lm_config := license_manager.LicenseManagerBasicConfiguration{
				OAuth:             false,
				ApiKey:            "your-api-key",
				SharedKey:         "your-shared-key",
				ProductCode:       "your-product-code",
				AuthData:          auth.FromKey("LICENSE-KEY"),
			}

lm, _ := license_manager.NewLicenseManager(
    lm_config,
    license_manager.WithHardwareId("your-HW-ID"),
)
```

```java
LicenseSpringConfiguration config = LicenseSpringConfiguration.builder()
  .identityProvider(customIdentityProvider)
  .build();
```

```python
class CustomHardwareIdProvider(HardwareIdProvider):
    def get_id(self):
        return "your_custom_hwid"

conf = Configuration(product="your_product_key",api_key="your_api_key",
                   shared_key="your_shared_key",file_key=key,file_iv=iv,
                   hardware_id_provider=CustomHardwareIdProvider)
```
:::

### Relink License

The license relinking method can be useful when the hardware ID algorithm has been changed. Despite the license belonging to the current device, the local check will throw **DeviceNotLicensedException** since different algorithms produce different hardware IDs. In this case you can relink the license to the new hardware ID. 

:::CodeblockTabs
```cpp
try
{
  license->localCheck();
}
catch(const DeviceNotLicensedException& ex)
{
  std::cout << "Trying to upgrade to newer hardware ID algorithm..." << std::endl;
  license = m_licenseManager->relinkLicense(HardwareIdGeneratorWindowsComputerSystemProductId);
  std::cout << "License successfully linked to new hardware ID." << std::endl;
  return;
}

// the C++ SDK also provides unlinkFromDevice and isLicenseBelongsToThisDevice methods
// unlinkFromDevice check if the license is tied to the current device, and deactivates it
// isLicenseBelongsToThisDevice checks if the license belongs to hardware ID computed by
// the passed DeviceIDAlgorithm
```

```csharp
try
{
  license.LocalCheck();
}
catch( DeviceNotLicensedException ex )
{
  Console.WriteLine( "Trying to upgrade to a newer device id algorithm..." );
  license = manager.RelinkLicense( DeviceIDAlgorithm.Gen3 );
  Console.WriteLine( "License successfully linked to new device id.\n" );
  return;
}
```
:::

This method checks if the old hardware ID of the license matches any of the IDs generated by different algorithms. When it finds the correct algorithm, it deactivates the license with the old ID and activates it again using the new algorithm. This method throws the same exceptions as a regular license activation.

## Recovering WMI

WMI repository issues can occur on Windows 10 and Windows 11. It's useful to know how to fix them since most of the hardware ID algorithms use WMI. Here are some recovery methods:

- To check if the WMI repository is consistent, open Command Prompt with administrator privileges and run `winmgmt /verifyrepository`. If you don't get a message stating `WMI repository is consistent`, proceed with the next steps.&#x20;
- In the same Command Prompt window, run the three following commands:
- `cd C:\Windows\system32\wbem`
- `mofcomp.exe CIMWin32.mof`
- `regsvr32 cimwin32.dll`
- You can also try to recover WMI by running the following command from Command Prompt with admin privileges: `winmgmt /resetrepository`  . For more information, see [**https://stackoverflow.com/a/71535626**](https://stackoverflow.com/a/71535626)
  Be aware of risks of running the command above, see [**https://techcommunity.microsoft.com/t5/ask-the-performance-team/wmi-repository-corruption-or-not/ba-p/375484**](https://techcommunity.microsoft.com/t5/ask-the-performance-team/wmi-repository-corruption-or-not/ba-p/375484)



[title] Custom Fields Usage
[path] SDKs/Tutorials/Best Practices/

At the heart of software development, custom fields stand as essential key-value pairs that empower developers to intricately define and deliver personalized information to end-users through licensing.&#x20;

This approach offers a range of applications, such as defining distinct license types like development, academic, government, or commercial, establishing designated account managers, facilitating seamless notification delivery, and even transmitting JSON data directly to the application.

This tutorial aims to help you grasp the use, implementation, and management of custom fields, enhancing your proficiency in software development.

::embed[]{url="https://www.youtube.com/watch?v=qvsAqdnxvmo&t=2s&ab_channel=LicenseSpringSoftware"}

## Prerequisites

1. Completed the [**Getting Started**](docId\:LSFY9tQ3vfq4ROOW9sHkd) Tutorial, including:
   - Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
   - Created a `LicenseID` using either `LicenseID::fromKey` or `LicenseID::fromUser` function, depending on the activation method you prefer.
   - Activated a license of any type.
   - Implemented routine local and online checks within the application.&#x20;

## Understanding Custom Field Usage

Some examples of usage scenarios for custom fields include:

### Product Identification and Differentiation:

With custom fields, you can effortlessly categorize multiple products under the same custom field key but with distinct values, streamlining differentiation.&#x20;

This minimizes code adjustments between product types, requiring only minor updates such as the product code and possibly a key and user information.&#x20;

Additionally, renaming a product becomes hassle-free – by creating a custom field for the product name and updating it on the LicenseSpring platform.

### Seamless Notifications:&#x20;

Imagine creating a custom field object labeled 'Notification' where the value serves as your notification message. Should you wish to modify your message, it's a breeze.&#x20;

Navigate to your product's custom fields, locate the 'Notification' key, and update the value with the new message.&#x20;

Once users update their licenses through online checks, the new notification message is seamlessly integrated.

### Tailored Edition Configuration:

Exploit custom field values to configure available editions for end-users without requiring separate software distributions.&#x20;

For instance, a `LicenseType` custom field could embody values like "lite," "standard," or "pro."&#x20;

Depending on the custom field value associated with a license, users can access different editions of the application, eliminating the need for multiple binaries.

## Defining Custom Fields

To integrate a custom field for your chosen product, start by navigating to the desired product.&#x20;

Within the interface, locate and click on the designated "Custom Fields" tab.&#x20;

Here, you'll find the option to initiate the customization process by selecting "Add Custom Field."&#x20;

On the pop-up, take the opportunity to define the default key-value pairing, effectively establishing the foundation for your custom field's configuration.

![How to define a new custom field.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/v2P1t8i0WabKH3xdCEMr4_image.png "How to define a new custom field.")

![Specify the default key-value pair for the new custom field.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/tvx1Bc7LipbaOZVaongIq_image.png "Specify the default key-value pair for the new custom field.")

## Adjusting Value of a Custom Field

Modifying the value of a custom field is a flexible option available to you at any point.&#x20;

:::hint{type="info"}
**Note:&#x20;**&#x54;o learn how to programmatically set a new value to your custom fields when issuing a license by looking at the documentation on our [**Order**](docId\:DfMlvcgLu4fHrne1qkNFh).
:::

Begin by generating the new license. For detailed instructions on how to issue a new license, refer to [**Issuing New Licenses**](docId\:fedDg9WixsYbHadHXYoL0).&#x20;

Once the new license has been created, locate it within the system and access the license screen.&#x20;

Here, you'll find the "Custom Fields" option; select it.&#x20;

![Navigate to the custom field of the license, and click on the pencil tool in order to edit the value.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/fjsIloJwKT1dHWtUtcjaq_image.png "Navigate to the custom field of the license, and click on the pencil tool in order to edit the value.")

Utilize the pencil tool to trigger a pop-up window, enabling you to modify the value associated with the custom field for that specific license.

![Set new value for your custom field.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/JLzt3tCGRry0yJSP_afcP_image.png "Set new value for your custom field.")

## Retrieving Custom Fields

A custom field essentially consists of a pairing of a key and a value. All the custom field data is stored within the local license.&#x20;

Accessing this data is achieved through:

:::CodeblockTabs
```cpp
std::vector<CustomField> customFields = license->customFields();
```

```csharp
CustomField[] customFields = license.CustomFields();
```

```java
List<CustomField> customFields = myLicense.getData().getCustomFields();
```

Swift

```swift
let customFields = license.customFields // [CustomField].
```

```python
response = license.custom_fields()

print(response)
```

```go
// Go SDK v2
fmt.Println(license_data.CustomFields)
```

```javascript
const license = licenseManager.loadLicense();
console.log(license.customFields);
```
:::

Upon license activation, whether through online or offline means, the resultant local license file encompasses all associated custom fields.&#x20;

Nevertheless, considering the dynamic nature of custom fields that can be introduced, removed, or modified post issuance and activation, an alternative method to refresh your local license file with any such alterations involves conducting an online check as shown one our [**License Checks**](docId\:ie-DAh13B4dqxMAQoYgrj) tutorial.

[title] Java Modules
[path] SDKs/Java SDK/

Learn what's supported in each SDK and more on this page dedicated to guiding you through the various Java SDK options and the features offered within each SDK.

![Java Module Structure](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/x8UA7DJrVkvnmPOtLfjPq_image.png "Java Module Structure")

## Client SDKs vs Management SDK

`License Client` and `Floating Client` modules are together referred to as "Client SDKs" and should be directly integrated within your application. These contain a separate API key and a shared secret which should be provided within configuration.

The `Management SDK` is meant to be used in a backend process somewhere within the purchase funnel, its code that should never reach your clients, as the SDK is meant to issue new licenses, modify their properties, list devices, etc. This is an optional integration which is required in cases where the entire `purchase -> license` model needs to be automated.

## License Client vs Floating Client

The `License Client`, historically, was the initial implementation of the LicenseSpring APIs, and it followed the designs and principles set in the other SDK implementations. As the interfacing is done via a `LicenseManager` class, which is a singleton, the `License Client` allows for only a single `License` per-process/class-loader paradigm. This means that only a single license is available for the application to use within this context.

The `Floating Client` was developed as a stand-alone module primarily to separate the floating license features from normal usage as these are quite different flows. But within this module, we've decided to allow for multi-license usage as there are some valid use-cases when a single license is not sufficient. For this reason there is no singleton implementation within the SDK, but a service has to be used when interfacing with LicenseSpring APIs.

The module sets up automated periodical checks of licenses activated, and releases licenses and deactivates the device on shutdown. Of course, all of this behavior may be disabled, but it's on by default as it sets up a very opinionated way of handling floating licenses. The `Floating Client`, by default, uses the PER\_PROCESS `Device Identification Strategy`, as the licenses are floating in a pool. This allows for the module to be very flexible, as some of the `Device` Identification issues on stacked virtualized environments are no longer an issue (virtual machine within virtual machine, docker within virtual machine, etc.).

## License Check Behavior

| Module              | Feature Name           | Feature Available | Default Behavior | Description                                                                                                       |
| ------------------- | ---------------------- | ----------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------- |
| **License Client**  | Periodic Check License | Yes               | No               | The license can be checked and synced periodically                                                                |
| **Floating Client** | Periodic Check License | Yes               | Yes              | All references to activated licenses are kept in memory , all of the active licenses are deactivated on shutdown. |
| **License Client**  | Subscribe to Check     | No                | No               | The only way to check the status is to call Check directly, or to `getCurrent` license from the manager.          |
| **Floating Client** | Subscribe to Check     | Yes               | No               | A custom implementation can be passed to respond to `Check` events (fail, success)                                |
| **License Client**  | Shutdown Hook          | No                | No               | There are no shutdown hooks, and they are not in the product road-map                                             |
| **Floating Client** | Shutdown Hook          | Yes               | Yes              | All references to activated licenses are kept, all of the licenses are deactivated on shutdown.                   |

## Multi-License, Storage, Caching

| Module              | Feature Name                     | Feature Available | Default Behavior | Description                                                                             |
| ------------------- | -------------------------------- | ----------------- | ---------------- | --------------------------------------------------------------------------------------- |
| **License Client**  | Multi-license                    | No                | No               | `LicenseManager` is a singleton class, will not change                                  |
| **Floating Client** | Multi-license                    | Yes               | Yes              | Multiple licenses, multiple products possible - via multiple LicenseService instances   |
| **License Client**  | Save license to disk (encrypted) | Yes               | Yes              | The license is saved to disk every time a check/(de)activation/consumption is performed |
| **Floating Client** | Save license to disk (encrypted) | No                | No               | The feature is not in the roadmap for `Floating Client`                                 |
| **License Client**  | Consumption Caching              | Yes               | Yes              | Currently unable to disable, will be possible in the future                             |
| **Floating Client** | Consumption Caching              | No                | No               | Currently only direct server calls, will be implemented in a future release             |

## Offline & Retry Features

| Module              | Feature Name                    | Feature Available | Default Behavior | Description                                                                                                                    |
| ------------------- | ------------------------------- | ----------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| **License Client**  | Offline Activation              | Yes               | No               | Licenses can be activated via offline file, no server will be called on any method.                                            |
| **Floating Client** | Offline Activation              | No                | No               | The feature is not in the roadmap for Floating Client                                                                          |
| **License Client**  | Retry on infrastructural errors | Yes               | No               | The mode can be activated in order to retry failed requests up to 5 times, with a back-off algorithm                           |
| **Floating Client** | Retry on infrastructural errors | Yes               | Yes              | The mode can be activated in order to retry failed requests up to 5 times, with a back-off algorithm                           |
| **License Client**  | Grace period on Check           | Yes               | No               | This mode uses `localCheck` when there are infrastructural issues, if the latest check license was within x configurable days. |
| **Floating Client** | Grace period on Check           | No                | No               | The feature won't be implemented due to time limitations imposed by floating model.                                            |


[title] SDKs
[path] /

LicenseSpring SDKs are designed to simplify the integration process, allowing you to focus on creating amazing software without the complexity of implementing licensing and protection mechanisms from scratch.&#x20;

## **Getting Started:**

Our documentation provides step-by-step guides, code examples, and best practices to assist you throughout the integration process. Whether you're a seasoned developer or just starting, our SDK documentation will guide you to success.

Choose your preferred programming language and platform, and dive into the world of streamlined licensing integration with LicenseSpring.

Explore our range of SDKs for [**C++ SDK**](docId\:vhNphrjIDMgaVkFh7laWx), [**.NET/C# SDK**](docId\:EE620oJMThwCyopGHOMfL), [**Python SDK**](docId:4_MQhgDD9DBw7MuCZlBKI), [**Java SDK**](docId:1aTXcepoYolBTnJWA0hH-), [**Delphi SDK**](docId\:QLZPKZXwM1J69_OML12xP), [**Go SDK**](docId\:wJx-38Wcnnw4U_lsvLUn2), [**Swift/Objective-C SDK**](docId\:aU3X3i1F0Z_yCq41LWhxh), [**Android SDK**](docId:4kECyKPcfpp5jdsgTtJXp), and [**Unity SDK**](docId\:eEUeH6Ox7PGWGQWgiY4aD), and take your software's licensing and protection to the next level.

## **Have Questions? Need Assistance?**

Our dedicated support team is here to help you every step of the way. If you have any questions, encounter issues during integration, or need guidance, don't hesitate to [**reach out to our support team**](https://licensespring.zendesk.com/hc/en-us/requests/new).&#x20;

We're committed to ensuring your licensing integration experience is smooth and successful.

[title] Java SDK Installation
[path] SDKs/Tutorials/Getting Started/Java/

The Java LicenseSpring SDK can be downloaded at [**Javadoc & Downloads**](docId\:Dm-Ksn9S-VVHGLpYWSm5x).

For this tutorial, we will download the Version 2.5.2 Core Jar and OSGi bundle, as well as the License Client Jar and OSGI bundle.

![Java JAR and OSGi Bundle Location](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/vLOmlKc6mIzqV1j_eNkuY_image.png "Java JAR and OSGi Bundle Location")

See [**Java Modules**](docId:-6YDRWccXDNLN9Fw4ZYa4) for more information about the different modules.

## Adding JAR Files and OSGI Bundles into Your IntelliJ IDEA Project

**Procedure:**

1. Open your installed IntelliJ IDEA Project&#x20;
2. Go to the **File > Project Structure**
3. Select **Modules** at the left panel and select the **Dependencies&#x20;**&#x74;ab.
4. Select the + icon and select **1 JARs or Directories** option.
5. Select your JAR file or you can select the directories.
6. Click on the **OK** button.

![Adding JAR Files to Dependencies](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/fKeqURBq7pKzob6l_m9LM_image.png "Adding JAR Files to Dependencies")


[title] C++ SDK
[path] SDKs/

Integrating software licensing into your C/C++ application is straightforward with the LicenseSpring SDK.&#x20;

Simply import our SDK into your project, and you're ready to go.&#x20;

If you don't find the binaries for your specific environment, contact our sales department.

:::hint{type="info"}
## **Supported Operating systems**

**Windows**

We support Windows 7 and later, and provide SDK builds created with

1. Visual Studio 2015 (v140), MSVC version 14.0, Windows SDK 10.0.19041.0
2. Visual Studio 2017 (v141), MSVC version 14.16, Windows SDK 10.0.26100.0
3. Visual Studio 2019 (v142), MSVC version 14.29, Windows SDK 10.0.26100.0
4. Visual Studio 2022 (v143), MSVC version 14.44, Windows SDK 10.0.26100.0
5. Visual Studio 2025 (v145), MSVC version 14.50, Windows SDK 10.0.26100.0

**Mac**

macOS 10.12 Sierra and later for the x86\_64 version and macOS 11.0 Big Sur and later for the ARM version, SDK was built with clang 9.0

**Linux**

At least Ubuntu 18.04 and 20.04 LTS are supported, SDK should work fine with any Linux distribution that can run GCC 7.5 with C++11/14. We provide SDK builds created with GCC 7.5 and 9.2.1

**Android**

Minimum Android API level 24 (Android 7.0 Nougat), targeting the `arm64-v8a, armeabi-v7a, x86, x86_64` ABIs, built with Android NDK 21.4.7075529, 26.1.10909125 and 27.2.12479018.
:::

:::hint{type="info"}
**New hardware ID generator library**

Since v7.42.0, we ship Windows, Linux and macOS C++ SDK releases with the SDK-independent hardware ID generator library. Each zip file on the download pages contains the binaries built for the platform you're downloading the SDK for.

See the [**Hardware ID generation**](docId\:yFnuCniXYZAno8e-sY5I1) page for more info.&#x20;
:::

## C++ SDK for Windows

Latest releases for Windows are available on the [**C++ SDK Windows download page**](https://sdk.licensespring.com/#Cpp/v7.48.1/Windows/).

## C++ SDK for macOS

Latest releases for macOS are available on the [**C++ SDK macOS download page**](https://sdk.licensespring.com/#Cpp/v7.48.1/Mac/).

:::hint{type="info"}
The x86\_64 version of the MacOS SDK was built with macOS SDK 10.12.

The ARM version of the MacOS LicenseSpring SDK was built with macOS SDK 11.3 and it's compatible with macOS SDK 11.0 and above.

The MacUniversal build contains both the x86\_64 and ARM binaries combined with [**lipo**](https://ss64.com/osx/lipo.html).
:::

## C++ SDK for Linux

Latest releases for Linux are available on the [**C++ SDK Linux download page**](https://sdk.licensespring.com/#Cpp/v7.48.1/Linux/).

:::hint{type="info"}
For legacy purposes, we provide a version of the C++ SDK built with the GLIBCXX\_USE\_CXX11\_ABI compiler flag set to 0.
:::

## C++ SDK for Android

Latest releases for Android are available on the [**C++ SDK Android download page**](https://sdk.licensespring.com/#Cpp/v7.48.1/Android/).

:::hint{type="info"}
Builds targeting Android systems don't use the SDK-independent hardware ID generator library. Instead, algorithms are compiled as part of the SDK.
:::

:::hint{type="danger"}
The build for **Centos 7** required installation of a newer version of a compiler (GCC) than one supplied in default system repositories.

GCC 7 is used from the centos-release-scl repository instead of a default 4.8.5.

Installation of a cmake3 is also required instead of 2.8 found in system repositories. The "epel" repository was used to obtain it.

These updates are also required in order to build samples.

**The build for Centos 7 is deprecated as of v7.33.0**.
:::

:::hint{type="info"}
When using a static library, you should define the LS\_STATIC symbol (e.g. in preprocessor definitions in VS).
:::

## Release notes

### January 22, 2026, v7.48.1

- Fixed validity period parsing in `LicenseSpring::UserLicense`.
- Added missing `LicenseSample.h` header to `CppSample.vcxproj`.
- Fixed incorrect VS toolset in project files all Windows samples in VS2015-VS2022 releases.
- Changed Windows SDK in project files for all Windows samples to `10.0` to allow building with Windows SDK versions other than 10.0.26100.0.
- Include `cstdint` header in `ExtendedOptions.h`, `InstallationFile.h`, `LicenseID.h` and `LicenseUser.h` headers for GCC 15 compatibility.

### January 14, 2026, v7.48.0

- Added an optional `redirectUri` parameter to `LicenseManager::activateLicense`, meant to be passed when using a non-default alternate redirect URI for single sign-on.
- Added `activateLicenseViaSSOAlternateRedirectUri` function to the C interface.
- Added support for getting multiple single sign-on URLs. The new, alternate SSO URLs differ from each other only by their redirect URI:
  - Added `BaseManager::getAllSSOUrls` method that returns a list of all available SSO URLs. The first element of the returned std::vector is considered the main SSO URL.
  - Added `LicenseHandler::getAllSSOUrls`.
  - Added `getAllSSOUrls` function to the C-interface.
  - Updated SSO sample to get all available SSO URLs from the License API.
- Added a feature to borrow licenses with SSO:
  - Added `License::borrow` overloads with SSO-related parameters.
  - Added `LicenseHandler::borrow` overloads with SSO-related parameters.
  - Added `borrowFloatingLicenseWithSSO` and `borrowFloatingLicenseTillWithSSO` functions to the C interface.
  - Added buttons for license borrowing in the SSO sample.

### December 9, 2025, v7.47.0

- Added debug dynamic libraries for Windows built with Address Sanitizer support:
  - Added LicenseSpringDAsan.dll and LicenseSpringAsan.lib binaries to DLL releases built with v143 and v145 toolsets
  - Added a `DebugDllAsan` configuration to the `LicenseSpringSamples` solution.
  - This release doesn't contain the ASan runtime library. Make sure to install it on your system.
- Updated the exception list in `BaseManager::createOfflineActivationFile` docstrings.
- Added additional exception logging messages after failing to generate offline request file.
- Added MinGW release missing from v7.46.0.

### November 27, 2025, 7.46.0

- Added a Windows release built with the v145 toolset (Visual Studio 2026, MSVC 14.50 and Windows SDK 10.0.26100.0).
- Updated Windows SDK for v141-v143 releases from 10.0.19041.0 to 10.0.26100.0.
- Updated v143 MSVC compiler version from 14.36 to 14.44.
- Removed v142 ARM64 release due to the combination getting deprecated in Windows SDK 10.0.26100.0
- Fixed a bug with generating malformed timestamps on some macOS machines using a non-English locale.
- Fixed detection of Linux Docker containers.
- Added missing `include` directory to macOS universal release.

### November 6, 2025, v7.45.0

- Added Windows releases targeting ARM64, built with VC142 and VC143 toolchains.
- Updated CMakeLists in all Qt-based samples to handle ARM64 for Windows.

### October 20, 2025, v7.44.0

- Migrated QtSample, AirGapQtSample and SSOSample to CMake.
- Replaced the `licensespring://...` custom URL handler to `licensespringsso://...` in SSOSample.
- Updated SSOSample to open the external browser and capture the custom URL on macOS.
- Removed deprecated Qt APIs from all Qt-based samples.
- Fixed libcurl, libssl and libykpiv versions in README.
- Fixed MinGW release not being published.

### October 13, 2025, v7.43.1

- Fixed DLL signing in Windows releases.
- Fixed CentOS 8 releases not being published.
- Fixed clang 19 release not being published.

### October 08, 2025, v7.43.0

- Added support for version 2 of the offline request schema.
- Fixed VM detection DLL loading on Windows targets.
- Fixed deactivating license locally when the License API returns a `license_not_active` error code on license deactivation.
- Updated libssl version to 3.5.4.
- Updated libcurl version to 8.16.0.
- Updated libykpiv version to 2.7.2.
- Linked secur32.lib to all static Windows targets, required by changes to libcurl, see [**https://github.com/curl/curl/pull/17413**](https://github.com/curl/curl/pull/17413)
- Updated CppSample to handle Floating Server V2.

### September 11, 2025, v7.42.0

- Added an x86\_64 Linux release (glibc 2.36), built with Clang 19 and linked to libc++ 19.
- Added a release for Android compiled with NDK 21.4.7075529, targeting the `arm64-v8a`, `armeabi-v7a`, `x86` and `x86_64` ABIs and minimum API level 24.
- Added a new multi-platform shared library that computes the hardware ID. See the `Hardware ID generation` page on our documentation for more information.
  - The default algorithm is unchanged on all platforms, and will not change at least until the next major release.
  - New algorithms are listed in the `LicenseSpring::DeviceIDAlgorithm` enum, starting from 100.
  - Added `hardware_id_generator.dll` binaries to Windows MSVC releases
  - Added `libhardware_id_generator.dll` binaries to Windows MinGW releases
  - Added `libhardware_id_generator.so` to non-Android Linux releases.
  - Added `libhardware_id_generator.so` to macOS releases.
  - On Windows, the dll must be located next to the built executable. On other platforms, it needs to be either next to the built binary, or in the RPATH of `libLicenseSpring`.

### August 26, 2025, v7.41.1

- Fixed automatic discovery of Floating Server V2.

### August 01, 2025, v7.41.0

- Fixed `include` directories not containing configured headers on macOS and Linux targets.
- Added support for Floating server V2 to `LicenseSpring::FloatingClient` and `LicenseSpring::License`.
- Made `BaseManager::reconfigure()` virtual to support overriding in `FloatingClient` class.
- Added a private `FloatingClient::m_isFloatingServerV2` member.
- Added `FloatingClient::getAllLicenses` method that fetches the `LicenseID` of available licenses from the Floating server tied to the configured product code.
- Added `FloatingClient::authenticateUser` method that allows a user to log in and use floating licenses.
- Added `ExtendedOptions::setCertificateChain`, `ExtendedOptions::setCertificateChainFromFile` and `ExtendedOptions::getCertificateChain` methods to set certificate chains user for verifying Floating Server V2 responses.
- Added `Configuration::getCertificateChain` getter.

### June 16, 2025, v7.40.0

- Added new Android builds targeting `armeabi-v7a`, `x86` and `x86_64` ABIs.
- Stripped unused debug symbols from shared libraries built with the Android NDK.
- Added `LicenseHandler::clearErrorInfo` method for manually clearing `LicenseHandler` error codes.
- Added `clearErrorInfo` function to the `LicenseHandler` C interface.
- Added `License::activationDate` and `License::activationDateUtc` license activation time getters.
- Added `LicenseHandler::getActivationDate` and `LicenseHandler:getActivationDateUtc` license activation time getters.
- Added `LicenseSpring::Company` class, used for getting the LicenseSpring company ID from the LicenseSpring backend.
- Added `Company` struct in the C interface with corresponding Create and Free functions.
- Added `License::company` and `LicenseHandler::getCompany` getters.
- Added `getCompany` function in C interface `LicenseHandler`.

### June 5, 2025, v7.39.0

- Fixed metadata JSON parsing in Android sample.
- Fixed a bug where calling `License::isLicenseBelongsToThisDevice` and `License::checkLicenseBelongsToThisDevice` would overwrite the set DeviceIDAlgorithm with one that doesn't belong to current device.
- Updated `License::isLicenseBelongsToThisDevice` and `License::checkLicenseBelongsToThisDevice` docstrings.
- Removed LDAP dependency for libcurl on static macOS targets.
- Fixed CppSample and CSample XCode projects crashing when linking to dynamic libraries.
- Added a BundleManager class which handles online and offline bundle activation and deactivation, and bundle checks.
- Added two new exceptions, `ProductNotBundleException` and `BundleMismatchException`.
- Added two new error codes, `eProductNotBundle` and `eBundleMismatch`.
- Refactored CppSample into two different subsamples, one with license activation, and one with bundle activation.
- Fixed a bug where signature verification fails when using custom white-labeled License API domains

### May 15, 2025, v7.38.0

- Fixed DESTDIR path for `win32` target in the Qt sample.
- Fixed an OpenSSL thread-safety issue when computing HMAC-SHA256.
- Added SDK builds for Android compiled with NDK 26.1.10909125 and 27.2.12479018, targeting the `arm64-v8a` ABI and minimum API level 24.
- Added an Android NDK sample to `samples/AndroidNDKSample`.

### April 18, 2025, v7.37.0

- Changed rpath for Linux libraries to `$ORIGIN`, which fixes `libLicenseSpring` not finding its dependencies provided by LicenseSpring.
- Added YubiKey support for licenses that require hardware key dongles:
  - On Linux and macOS targets, new libraries are placed in `bin/shared_HardwareKey` and `bin/static_HardwareKey`. Libraries in `bin/shared` and `bin/static` work as expected without linking to `libykpiv`.
  - Linux versions targeting `arm` and `ppc64le` don't link to `ykpiv`.
  - On MSVC targets, new libraries are placed in `bin/dynamic_HardwareKey`. We don't support static linking to `libykpiv`.
  - Added a new class `LicenseSpring::HardwareKeyOptions` used for fetching YubiKey serial numbers, and setting the YubiKey PIN and serial.
  - Added a `LicenseSpring::HardwareKeyOptions` setter and getter to `LicenseSpring::ExtendedOptions`
  - Added the corresponding C inteface for `LicenseSpring::HardwareKeyOptions`
  - Added a new exception `LicenseSpring::HardwareKeyException` and corresponding LicenseSpring error codes.
- Added an optional `password` parameter to `License::borrow` and `LicenseHandler::borrow` that allows borrowing user-based licenses.
- Added `borrowFloatingLicenseWithPassword` and `borrowFloatingLicenseTillWithPassword` functions to the `LicenseHandler` C interface.

### April 8, 2025, v7.36.0

- Update OpenSSL to version 3.4.1
- Update curl to version 8.12.1
- The SDK now throws `LicenseSpring::OAuthException` when sending an unknown `client_id` OAuth parameter.
- The SDK now throws `LicenseSpring::OAuthException` when sending a malformed OAuth token.
- Added `eInvalidClient` error code to `LSErrorCode`.
- Added `eOAuthTokenMalformed` error code to `LSErrorCode`.
- Prolonged lifetime of the internal Logger singleton and the internal OpenSSL crypto provider by marking their constructor invocations with \[\[gnu::constructor]]. This change is relevant only for gcc and clang compilers.
- Added overload for `BaseManager::getProductDetails` that retreives product-level custom fields and filters products by environment string.
- Added overload for `LicenseHandler::getProductDetails` that retreives product-level custom fields and filters products by environment string.
- Added `getProductDetailsWithCustomFieldsAndEnv` function in C-interface for `LicenseHandler`.
- Added `ProductDetails::customFields` getter.
- Added `customFields` getter in C-interface for `ProductFields`. See `CSample` for usage instructions.
- Updated `CppSample` and `CSample`.
- Changed code formatting rules in header files.

### February 20, 2025, v7.35.0

- Added OAuth client credentials authentication to the License API.
- Added a factory function `Configuration::CreateOAuth` for OAuth authentication.
- Added a factory function `CreateLSConfigurationOAuth` to the C interface.
- Added `Configuration::isOAuth`, `Configuration::getClientId` and `Configuration::getClientSecret`.
- Added the same getters to the C interface.
- Updated samples with OAuth, see `AppConfig.cpp` and `AppConfig.c`
- Added `setCryptoProviderKey` and `setCryptoProviderSalt` setters to the C interface for `ExtendedOptions`. Using the key setter is required for OAuth authentication.

### February 14, 2025, v7.34.0

- Added a new licensing agreement for the SDK.
- Added overloads for online and offline activation functions, which enables sending device variables on licnese activation.
- Added `License::isNegativeConsumptionAllowed`, `LicenseHandler::isLicenseNegativeConsumptionAllowed` and corresponding C interface getters.
- Fixed memory leak in Windows hardware ID algorithm.
- Added `License::orderStoreId` and `LicenseHandler::getOrderStoreId` and corresponding C interface getters for the order store ID.
- Fixed a crash when calling `License::registerFloatingFeature` and `License::releaseFloatingFeature` with the offline floating server.
- Changed certificate bundle SSL verification to check multiple bundles on the filesystem.
- Improved logging on failed SSL verification.

### &#xD;September 03, 2024, v7.33.0

- Fixed license object not updating after license relink in `CppSample`.
- Fixed `License::validityWithGracePeriod` and `License::validityWithGracePeriodUtc` adding extra hour in case of DST.
- Added more verbose error messages for license file writing.
- Added `ExtendedOptions::enableLicenseCorruptionCheck`, `ExtendedOptions::isLicenseCorruptionCheckEnabled` and `Configuration::isLicenseCorruptionCheckEnabled` and associated C interface functions, see SDK documentation for more details.
- Added `BaseManager::isLicenseFileCorrupted` and associated `LicenseHandler` and C interface functions.
- Fixed hardware ID validation on cloud provider algorithms.
- Added license signature validation to `License::localCheck`.
- Added curl connection timeout setter and getter to `ExtendedOptions`, `Configuration`, and corresponding C interfaces.
- Added new `UserLicense` and `UserLicensesData` classes to encapsulate information about multiple licenses of the same product assigned to a single user.
- Added `LicenseManager::getUserLicenses` and `LicenseHandler::getUserLicenses` to retrieve `UserLicensesData` objects from the license API.
- Added a new `LicenseID::fromUser` constructor that takes a server-side license ID parameter from `UserLicensesData`.
- Added `License::serverId` and `LicenseHandler::getLicenseServerId`.
- Updated the user-based C++ sample.
- Changed return values of `LicenseHandler::licenseFileName` and `LicenseHandler::licenseFilePath` to `const std::wstring&` for C interface compatibility.
- Deprecated the CentOS 7 SDK build.

### &#xD;May 24, 2024, v7.32.0

- Fixed generating hardware ID on AWS instances.
- Improved memory handling of License API wrapper.
- Added air-gapped license pre-provisioning through online activation.
- Added `getDataLocation`, `setDataLocation`, `getLicenseFileName`, `setLicenseFileName` functions to the C `LicenseHandler` interface.
- Fixed offline license update throwing `ProductMismatchException`.
- Implemented `ProxySettings::fetchProxySettings` that tries to automatically fetch current user proxy settings

### &#xD;April 19, 2024, v7.31.0

- Fixed certificate lookup on macOS.
- Fixed documentation for `License::feature`.
- Added `License::trialPeriod` member function, which returns the trial duration of the current license.
- Fixed `DeviceIDAlgorithm::WinCSProductId` failing on Windows startup.
- Added more robust check of tampered VM detection DLL.
- Froze the MSVC compiler version to 1936 (runtime library version 14.36.32532) in the v143 toolset Windows build.

### &#xD;February 24, 2024, v7.30.0

- Added new hardware ID algorithm `DeviceIDAlgorithm::AutoIdWinCloud` that tries to compute `CloudPlatformsId` with `WinCSProductId` as the fallback.&#x20;
- Fixed `BaseManager::reconfigure` crashing the SDK.

### &#xD;February 09, 2024, v7.29.0

- Added `License::transferLimit` member function, which returns the limit of license transfers between devices.
- Added `License::isDeviceTransferAllowed` and `License::isDeviceTransferLimited` member functions.
- `License::syncFeatureConsumption` now correctly throws the `NotEnoughConsumptionException` exception.
- Added optional `includeExpiredFeatures` parameter to `License::check`.
- Updated CppSample and CSample to print device transfer info.
- Updated CppSample and CSample to get expired features.

### &#xD;January 08, 2024, v7.28.1

- Fixed handling older non-floating features.
- Fixed getting product details in the C SDK sample.

### &#xD;December 12, 2023, v7.28.0

- Added handler for `license_user_activated_max_times` error code, the SDK throws `LicenseNoAvailableActivationsException` in case of this error on license activation.
- Fixed floating in use count parsing for offline floating licenses.
- Added floating feature registration and releasing.
- Added floating feature watchdog.
- Added optional flag `includeLatestVersion` to `LicenseManager::getProductDetails`.
- Implemented `ProductDetails::latestVersion()` getter.
- Updated CppSample and CSample to handle floating features, floating feature watchdog and latest version.

### &#xD;October 11, 2023, v7.27.1

- curl updated to v8.4.0

### &#xD;August 31, 2023, v7.27.0

- Fixed issues in .xcodeproj files for C and Cpp SDK samples.
- Improved MinGW SDK build, added VM detection dll.
- Updated certificates bundle file.
- Updated static libraries for Windows MSVC.

### &#xD;August 25, 2023, v7.26.1

- Fixed false positive malware detection in Virtual Machine detection module.
- Fixed false positives and improved detection of Hyper-V.

### &#xD;August 21, 2023, v7.25.0

- Added CMake build for CppSample on Windows(MSVC).
- Added logging to air-gap activation.
- Implemented grace period feature.
- Added `isGracePeriodStarted`, `gracePeriodEndDateTime`, `gracePeriodEndDateTimeUTC`, `gracePeriodHoursRemaining` methods to `License` class.
- Added `setGracePeriod`, `getGracePeriod` methods to `ExtendedOptions` class.
- Added `RequestDateInvalidException` and `eRequestDateHeaderInvalid` error code.
- Renamed methods related to subscription grace period to `License::isSubscriptionGracePeriodStarted`, `License::subscriptionGracePeriod`.
- Fixed handling of absolute paths on MacOS and Linux.
- Fixed issues with false positive VM detection, improved logging for VM detection module.
- Fixed incorrect metadata deserialization issue.
- OpenSSL updated to v3.1.2.
- curl updated to v8.1.2.

### July 14, 2023, v7.25.0

- SSL certificate verification now enabled by default
- Moved verification of confirmation code to the `activateAirGapLicense` method
- Added `AirGapActivationException`, it occurs when confirmation code verification fails
- Added `LicenseHandler::isLicenseAirGapped `and `License::isAirGapped` methods
- Added `LicenseHandler::getLicensePolicyId` and `License::policyId `methods
- Added improvement: loading license if exist when changing license data location, see `setDataLocation`
- Added signature verification when handling license borrowing response
- Added missing options to Configuration and ExtendedOptions structs for C-interface
- Added to C-interface `LSExtendedOptions` *setAlternateKey* function that accepts C-string
- Added subset of embedded certificates, improved logic for SSL certificate verification and lookup
- Added support for Schannel TLS backend for curl on Windows
- Added support for Secure Transport TLS backend for curl on macOS
- Implemented feature of loading ca certificates from OS and ca bundle file
- Implemented caching of product details, added `License::productDetails `method
- Implemented air-gap license deactivation, added `License::deactivateAirGap` and `License::getAirGapDeactivationCode` methods
- Updated AirGapQtSample to handle air-gap deactivation
- Fixed air-gap trial license detection issue
- Fixed confirmation code verification issue for air-gap licenses
- Fixed signature verification issue when using older versions of libcurl
- Fixed signature verification issue for older API
- Fixed prepending slash path issue when setting license data location
- Fixed issues with Unicode symbols in license file path for macOS and Linux
- Improved exception handling
- Improved alternative device id creation on Linux
- Improved air-gap activation security

### June 12, 2023, v7.24.0

- Added metadata field for `ProductDetails`, `Customer`, `License` and `LicenseFeature` classes.
- Added logging and handling exceptions to license watchdog.
- Added `WatchdogException`, it occurs in case creating watchdog thread failed.
- Added `ExtendedOptions::setAlternateKey` method that accepts string.
- Added minor improvements and logging for offline activation.
- OpenSSL updated to v1.1.1.21(u)
- curl updated to v8.1.2
- Fixed issue of creating a log file when logging is disabled.
- Security patch, that address vulnerability of bypassing license signature verification.



### May 17, 2023, v7.23.0&#xD;

- Updated SDK demo samples. Implemented better handling of floating licenses in WinSample, CSample and CppSample.
- Implemented unlimited consumption feature. Added `License.isUnlimitedConsumptionAllowed` , `LicenseFeature.isUnlimitedConsumptionAllowed` and `LicenseHandler.isLicenseUnlimitedConsumptionAllowed` methods.
- Fixed issue of saving local license after revoking floating license.
- Fixed issues with error handling for offline and air-gap activation.
- Fixed OS version detection issue for Windows 11.

### April 27, 2023, v7.22.0&#xD;

- Improved security check for offline license activation and refresh, implemented offline signature verification.
- Improved error handling for offline license activation and refresh, the SDK will throw more specific exceptions in case of errors.
- OpenSSL updated to v1.1.1.20(t)
- curl updated to v8.0.1
- Updated JSON for Modern C++ to v3.11.2
- Fixed issue of json serialization when license data contains invalid UTF-8 bytes.

### April 04, 2023, v7.21.0&#xD;

- Included cURL and OpenSSL header and lib files.
- Added README file with cURL and OpenSSL version information.
- Added SDK version to log file.
- Added new device id algorithms `DeviceIDAlgorithm::Gen2` and `DeviceIDAlgorithm::AutoIdGen2`.
- Improved security for `License::updateOffline` method.
- Fixed several issues with offline activation.
- Fixed `LicenseManager::relinkLicense` method.
- Fixed issue of encrypting long strings.

### February 08, 2023, v7.20.0&#xD;

- Added `ApiKeyException `and corresponding error codes `eInvalidApiKey`, `eReadOnlyApiKey`, `eRevokedApiKey `and `eApiKeyProductNotAllowed`.
- Added `FloatingTimeoutExpiredException`.
- Implemented `License::maxBorrowTime` method.
- Implemented grace period feature for Subscription licenses. See `License::gracePeriod` and `License::validityWithGracePeriod`.
- Implemented `License::isGracePeriodStarted` method.
- Fixed issue of auto-revoking floating license at app exit when using static `LicenseHandler`object.
- Fixed error handling for successful responses during license activation and online check.
- Fixed issue of missing mac SDK version information.
- Improved floating expiration logic and local license check.
- Removed `License::signature`, implemented faster loading and saving of local license.

### January 09, 2023, v7.19.0&#xD;

- Implement support for duration fields in license policy file for Air-gap activation.
- Implemented a couple of alternative device id algorithms for Windows. See `DeviceIDAlgorithm::WinCSProductId` and `WinCryptographyId`.
- Implemented `relinkLicense`method.
- Added `License::stopLicenseWatchdog` method, same added for `LicenseHandler` and C-interface.
- Fixed issue with incorrect rpath for mac universal dynamic libs.
- Improved error handling in case license transfer is limited or not allowed.

### October 24, 2022, v7.18.0&#xD;

- Improved security, implemented license signature v2 verification.
- Implemented `setupLicenseWatchdog` function for C-interface.
- Implemented SSO activation using auth code.
- For Windows builds VM detection code is moved to satellite DLL.
- Fixed issue of incorrect return value for `LicenseHandler::getMaintenanceDaysRemaining` method.
- Fixed several problems with Linux machine id in some of the distributions and Docker containers.
- Updated SSOSample and CSample.
- Updated documentation.

**Note:**

Starting from v7.18.0 the VM detection module for Windows has been moved to LSVMD.dll. This dll is present in the SDK zips. Customers need to distribute this dll with their applications only if they use the Virtual Machine Detection detection for Windows, it can be simply ignored otherwise and not distributred.

The LicenseSpring C++ SDK loads this dll at runtime when checking if current Windows is a Virtual Machine. There is no need to link against it when building your application. LSVMD.dll cannot be used outside of LicenseSpring and the SDK checks whether the dll is tampered before using functions from it.


### August 15, 2022, v7.17.0&#xD;

- `FloatingClient::borrow` renamed to `FloatingClient::borrowLicense`.
- Implemented getting instance id for cloud platforms: AWS, Azure, and GCP. Added `DeviceIDAlgorithm::CloudPlatformsId` and `DeviceIDAlgorithm::AutoId`.
- Fixed issue of virtual methods in `LicenseFeature` class.
- Implemented error handling for 401, 403, 407 http errors. See `AuthorizationException` and `eAuthorizationError` error code.
- Added device variables to offline deactivation file.

### July 22, 2022, v7.16.0&#xD;

- Implemented methods `getAirGapActivationCode`, `verifyConfirmationCode` and `activateAirGapLicense` in `LicenseManager` and `LicenseHandler` classes for activation of air gap licenses.
- Added `DeviceIDAlgorithm` enum and `ExtendedOptions::setDeviceIdAlgorithm` function. `DeviceIDAlgorithm::Gen1` option can be useful for air gap activation.
- Added `Configuration::isSSLCheckEnabled` and `ExtendedOptions::enableSSLCheck`, see SDK documentation for more details.
- Added `Source: sdk` header.
- Added `FloatingClient::borrow` method.
- Added AirGapQtSample project.
- Improved SSOSample, added support for authorization with default browser.
- Implemented sending optional param `sdk_lang`.
- Implemented `License::isBorrowed` and `LicenseHandler::isLicenseBorrowed` methods.
- Fixed virtual destructors and header files for CryptoProvider and LicenseStorage.
- Fixed setting license file path and name through the LicenseHandler.
- Fixed instantiating locale issue for older libcxx versions.
- Fixed several issues and improved SDK \<-> FloatingServer integration.
- Updated SDK documentation.

### May 31, 2022, v7.15.0&#xD;

- Improved integration with Floating server.
- Updated SDK documentation.
- Added `LicenseID::setPassword` method.
- Added methods for consumption licenses: `License::consumptionPeriod`, `License::isResetConsumptionEnabled`, `LicenseHandler::isResetLicenseConsumptionEnabled`, `LicenseHandler::getLicenseConsumptionPeriod`.
- Added methods for consumption license features: `LicenseFeature::maxOverages`, `LicenseFeature::isOveragesAllowed`, `LicenseFeature::consumptionPeriod`, `LicenseFeature::isResetConsumptionEnabled`.
- Fixed typo in `Configuration::isLoggingEnabled` method.
- Fixed detection of OS name for Windows 11.

### May 12, 2022, v7.14.0&#xD;

- Implemented license borrowing feature. See `License::borrow`, `LicenseHandler::borrowFloatingLicense`.
- Added `License::floatingEndDateTime`, now floating license expires when floating period ends.
- Added `LicenseHandler::registerFloatingLicense` method, it is equivalent to online license check for cloud floating license.
- Added `BorrowLicenseException` and `eBorrowLicenseError`, `eBorrowingNotAllowed` error codes.
- Added `Configuration::setUserInfo` and `Configuration::getUserInfo` methods for passing generic user defined data to the backend.
- Added `LicenseID::trim`, license identifier will be automatically trimmed if you use `LicenseID::from...` function.
- Fixed several minor bugs and W4 warnings, stability and performance improvements.

### April 19, 2022, v7.13.0&#xD;

- Implemented new API set for managing device variables. See `DeviceVariable`, `License::getDeviceVariables`, `License::addDeviceVariable` etc. Now device variables a being stored along with local license, managing device variables available both locally and on the backend. See SDK documentation for more details.
- Fixed problem of auto-revoking floating license.
- Implemented adding consumption for offline-floating license.
- Added `License::registerFloatingLicense` method.
- Updated `TestFloatingServer` function for CppSample.
- Fixed name conflict with Google Test Framework in EncryptString.h

### March 31, 2022, v7.12.0&#xD;

- Added SDK build for VC143 (Visual Studio 2022)
- Improved network communication security.
- Added address info data to the `Customer` class (address, city, state, country, postcode).
- Implemented ability to set desired license policy when requesting trial license. See `LicenseManager::getTrialLicense`.
- Fixed issues with `FloatingClient::registerLicense` and `FloatingClient::isOnline`.

### March 16, 2022, v7.11.0&#xD;

- Implemented Single sign-on (SSO) feature. See `LicenseManager::getSSOUrl` and `LicenseManager::activateLicense` using token.
- Implemented `ExtendedOptions::setAlternateKey`, `ExtendedOptions::setAlternateServiceURL` methods.
- Added SSOSample.
- Added `FileStorageWithLock` implementation for Linux and macOS.
- Added `License::startDate` method and `CannotBeActivatedNowException`, see SDK docs for more details.
- Added new exceptions: `SSOException`, `SSOTokenException` and `TrialNotAllowedException`.
- Fixed issue of incorrect license status in case license is copied from other device (in case of device id mismatch).

### November 17, 2021, v7.10.0&#xD;

- Added `LicenseUser::isInitialPassword` method.
- Fixed issue with license file path on Linux and macOS.
- Improved performance of API requests.

### November 3, 2021, v7.9.0&#xD;

- Added new class `FileStorageWithLock` for license synchronization between threads and processes.
- Added data check when sending device variables.
- Improved support of handling multiple licenses, added `BaseManager::reloadLicense` method.
- Improved loading and saving local license to file, updated documentation.
- Improved mutex management in `LicenseFileStorageEx` class.
- Fixed bad locale name issue on some platforms.

### October 04, 2021, v7.8.0&#xD;

- Added new methods `License::isAutoReleaseSet` and `License::setAutoRelease`, the same for `LicenseHandler`.
- Added new class `LicenseUser`, see also `License::licenseUser`. Implemented getting license user info when activating or checking a license.
- Implemented new API request `LicenseManager::getLicenseUsers`
- Added SDK sample for Qt Framework ([**https://qt.io**](https://qt.io)), see samples/QtSample.
- Added SDK sample for JUCE Framework ([**https://juce.com**](https://juce.com)), see samples/JUCESample.
- Fixed issue with removing local license, `clearLocalStorage` method now also removes license data from memory.
- Fixed issue with localized dates in requests signature.

### September 15, 2021, v7.7.0&#xD;

- Added new methods to `LicenseHandler` class, see `LicenseHandler::dataLocation` and `LicenseHandler::setLicenseFileName`.
- Added new documentation for `BaseManager` class.
- Improved LicenseStorage classes, added new class `LicenseFileStorageBase`.
- Fixed logging issues.

### September 01, 2021, v7.6.0&#xD;

- Added new classes `CryptoProvider`and `DefaultCryptoProvider`. Now it is possible to set crypto key or salt, or implement custom `CryptoProvider`.
- Added new license data fields, see `License::transferCount` and `License::floatingInUseCount`.
- Added ability to reset local consumption when updating license offline, see `License::updateOffline`.
- Implemented new license storage model. See `LicenseStorage` abstract class and `LicenseMemoryStorage`, `LicenseFileStorage` classes. Now it possible to store local license in custom locations like your DB, Windows registry, etc, by implementing `LicenseStorage`.
- Implemented interprocess synchronization for local license, see `LicenseFileStorageEx` class.
- Implemented security improvements for offline activation (offline activation guards). See `ExtendedOptions::enableGuardFile`.
- Improved `FloatingClient`, see changes in `FloatingClient::register/unregister` and `License::floatingClientId`.
- Improved handling of `InstallationFiles`, added helper struct `InstallFileFilter`, updated `LicenseHandler` and C-interface.
- Improved VM detection, fixed false positive detections.

### August 02, 2021, v7.5.0&#xD;

- `LicenseManager::getTrialLicense` now returns `LicenseID`, that incudes initial password for user-based products.
- Implemented `License::updateOffline` and `LicenseHandler::updateOffline` functions, that allow offline license updates.
- Added new fields to `InstallationFile` class: Environment, Eula Link, Release Notes Link, Size and Channel.
- Implemented filtering of installation files by Environment and Channel.
- Added local consumption information to offline deactivation files.
- Added `ClockTamperedException` instead of `DateTimeCheatingException`.
- Fixed issue when deleting floating license.

### June 9, 2021, v7.4.0&#xD;

- Implemented new classes for interaction with on-premise floating server. See `FloatingClient`, `FloatingServerInfo`.
- Added new members to `InstallationFile` class, that allows implementing of intermediate updates. See `InstallationFile::releaseDate` and `InstallationFile::requiredVersion`.
- Security improvements, encrypted internal SDK data, added header file for strings encryption see EncryptString.h.
- Added SDK build for Mac ARM64 target architecture.
- Improved error handling.
- Updated JSON for Modern C++ to v3.9.1
- OpenSSL updated to v1.1.1k
- curl updated to v7.77.0

### March 17, 2021, v7.3.0&#xD;

- Implemented feature for requesting overage for consumption licenses, see `License::syncConsumption`.
- Added new class `NetworkInfo` and implemented feature allowing override IP, MAC and host name determined by default. See `ExtendedOptions::overrideNetworkInfo`.
- Fixed false positive detection of Windows VMs.
- Improved and optimized VM detection for Windows.
- Fixed memory leak issue in static library due to missing OpenSSL resources cleanup in curl.
- Improved WinSample.
- Removed `OptionalProperties` class.

### February 26, 2021, v7.2.0&#xD;

- Implemented expiry date for `LicenseFeature` class, see `LicenseFeature::expiryDate` and `LicenseFeature::isExpired`.
- Fixed COM initialization issue in VM detection module.
- SDK build for Linux with GCC 7.5 now has no dependency to std::filesystem.
- Fixed static linkage issue in CSample.
- Improved WinSample.

### February 15, 2021, v7.1.0&#xD;

- Added new feature for storing user data inside license file, see `License::addUserData`, `License::removeUserData` and `License::userData`
- Added new class `OptionalProperties` for sending optional parameters when checking license.
- Allowed decreasing consumption, see new methods `License::updateConsumption` and `License::updateFeatureConsumption`.
- curl updated to v7.75.0
- Created SDK build for Linux compiled with GCC 7.5
- Added Xcode proj files for SDK samples.
- Build for macOS now supports macOS 10.12 Sierra and latter.

### January 19, 2021, v7.0.0&#xD;

- **Implemented C-interface**, see header files inside include folder and CSample.
- Main namespace was renamed to `LicenseSpring`.
- Most of the classes have been reworked and improved.
- Fixed `License::daysRemaining` counter.
- Added new class `LicenseID`, generalized API calls for user-based and key-based products.
- Added Documentation.
- Removed Management API (classes `ManagementService`, `LicenseDetails`, `OrderDetails`) from the SDK, if you need access to Management functionality please use API directly or through the Java SDK.

### November 20, 2020, v6.2.0&#xD;

- Implemented change password feature for user-based Products. See `LicenseManager::changePassword` and `License::changePassword`.
- Added helper method `License.maintenanceDaysRemaining`.
- Improved error handling when reading/writing license.
- Dynamic libraries have been digitally signed.
- Fixed minor linking issues on Linux.
- Fixed static libraries for Windows, disabled /GL compiler switch.
- Fixed redirection issue.
- cUrl updated to v7.72.0

### June 16, 2020, v6.1.0&#xD;

- Implemented new `LicenseHandler` class, it is now part of the LicenseSpring library.
- Fixed LicenseWatchdog timeout issue.
- Fixed license data update during online check.
- Experimental filesystem replaced with std filesystem for Linux build.
- A few methods of the `LicenseManager` class were renamed.

### June 8, 2020, v6.0.0&#xD;

- Implemented VM Detection feature. See `License::isVMAllowed`, `LicenseSpringExtendedOptions::enableVMDetection` and `LicenseSpringConfiguration::isVM`.
- Implemented Floating licensing and LicenseWatchdog. See `License::isFloating` and `License::setupLicenseWatchdog`.
- Implemented Overages feature for Consumption license type. See `License::isOveragesAllowed` and `License::maxOverages`.
- Added new classes `BaseManager` and `ManagementService`. Functionality divided into management and en-user license handling.
- Added new exception types `VMIsNotAllowedException`, `MaxFloatingReachedException` and `DeviceBlacklistedException`.
- Updated `LicenseDetails` and `OrderDetails` classes, added new data fields.
- Thread safety and reliability improvements.
- Architecture changes and enhancements, LicenseManager no longer a singleton.
- Fixed TLS version issue.
- Third party libs updated to latest stable versions (OpenSSL 1.0.2u, cURL 7.70+).

### May 5, 2020, v5.5.2&#xD;

- Fixed hostname issue for Windows systems.
- Fixed problem with `ProxySettings`.
- Added new exception type `LicenseNoAvailableActivationsException`.

### April 28, 2020, v5.5.1&#xD;

- Fixed consumption features update.
- Improved error handling.

### April 24, 2020, v5.5.0&#xD;

- Implemented increase feature consumption in offline mode.
  Improved consumption handling.
- Added new methods `License::updateFeatureConsumption`, `LicenseFeature::localConsumption`.
- Added helper method `License::feature`, it returns feature by code.
- Improved error handling and added new exception class `InvalidLicenseFeatureException`.

### April 10, 2020, v5.4.4&#xD;

- Improved error handling and fixed a few minor bugs.
- Added new exceptions `MissingEmailException` and `InvalidOrderIDException`.

### March 31, 2020, v5.4.3&#xD;

- Added new helper method `LicenseManager::isOnline`, for more details see header file.
- Improved `License::increaseFeatureConsumption`, removed redundant check and increased performance.
- For Windows default license file path changed to %localappdata%\LicenseSpring%ProductCode%\license.key If you use default license path in your app license will be transferred to new location by the SDK automatically.
- Added `UnknownLicenseSpringException` class.
- Improved `LicenseHandler` class.
- `License:sendCustomData` renamed to `License::sendDeviceData`.
- Added new build for Linux that compatible with old ABI.

### March 25, 2020, v5.4.1&#xD;

- Added `LicenseFeature::name`, now it's possible to get License feature name not only code.
- Added helper method `License::isMaintenancePeriodExpired`.
- Fixed deactivation bug, timesActivated value wasn't updated properly. Improved online deactivation, see `License::deactivate`.
- Fixed hardware ID issue for Windows systems where system disk or other piece of hardware could not be determined.
- Fixed linking errors for Linux build.

### &#xD;March 04, 2020, v5.4.0&#xD;

- Added new `LicenseManager::getTrialLicense` method. It accepts Customer ptr, when issuing trial license also new customer will be created or license will be assigned to existing customer.
- Added `License::lastCheckDateUtc` and fixed `License::daysRemaining` method, see header file for more details.
- Added logging, see `LicenseSpringExtendedOptions::enableLogging`.
- Improved hardware ID detection for Linux systems.
- Fixed issue of consumption features. Consumption changes were not stored to local license file properly.
- Fixed Unreal Engine compatibility issues, `ProxySettings` and `LicenseSpringExtendedOptions` became classes instead of structs.
- Stability and performance improvements.

### January 28, 2020, v5.3.1&#xD;

- Fixed issue with company data member in Customer class.
- Added `OrderDetails::setOrderID` method.

### January 27, 2020, v5.3.0&#xD;

- Added license owner information, see `License::owner` and console sample.
- Fixed Hardware ID issue in case of foreign (not english) locale.
- Fixed issue of consumption license features.
- Added exception in case HOME system variable is unavailable (applicable for Linux and Mac OS X).

### December 27, 2019 v5.1.0&#xD;

- Added new API request `LicenseManager::getProductDetails`, new class `ProductDetails`.
- Added `LicenseSpringConfiguration::getLicenseSpringAPIVersion` method. It returns API version that SDK uses.
- API version field added to offline activation/deactivation.
- `LicenseManager::getTrialKey` replaced with `LicenseManager::getTrialLicense`.
- Improved `LicenseManager::createOrder`, new class `LicenseDetails`.
- Improved console sample, now demonstrates both user-based and key-based licensing approaches.

### December 11, 2019, v5.0.0&#xD;

- User-based licensing.
- New classes `Customer` and `OrderDetails`.
- Added requests for creating licenses and orders. See `LicenseManager::createLicense` and `LicenseManager::createOrder`.
- Consumption license features. See `License::features`, `License::increaseFeatureConsumption` and `LicenseFeature` class.
- Added new methods `License::maxActivations` and `License::timesActivated`.
- Added ability to track MAC address. `CollectHostNameAndLocalIP` renamed to `CollectNetworkInfo`.
- `LicenseHandler` SDK wrapper class, it helps handle SDK exceptions in one place.
- New classes for managing app versions, see Version.h.
- Improved samples.
- Stability and performance improvements.

### September 24, 2019, v4.6.0&#xD;

- New API request `License::sendCustomData`, it allows sending custom data to the platform. Data will be linked to a device, so on the platform see device variables.
- Changed license status logic, now it's possible to check whether license is active even if it was disabled. See `License::isActive`, `License::isEnabled` and `License::status`.

### September 19, 2019, v4.5.3&#xD;

- Fixed online license check and hardware ID issue
- New helper class `Version`, helps compare app versions, during update for example
- Minor performance improvements and improved WTL sample

### September 15, 2019, v4.5.2&#xD;

- Fixed `License::isOfflineActivated` method
- Improved SDK sample apps

### September 12, 2019, v4.5.1&#xD;

- Improved error handling, added new error codes `eLicenseDisabled` and `eLicenseInactive`
- `LicenseExpiredException` has been removed. Now in case of expired license the SDK throws `LicenseStateException` with eLicenseExpired error code
- Fixed online license check
- Fixed offline activation in UI sample

### September 9, 2019, v4.5.0&#xD;

- Added new feature - Custom product (license) data fields, see `License::customFields` and CustomField.h
- All exceptions now have error code, see LicenseSpringErrorCodes.h
- Added new sample with GUI, it's native Windows app based on WTL (Windows Template Library)
- Added `License::MaxDaysRemainingValue` constant
- Fixed sending of optional parameters app name and version

### August 19, 2019, v4.4.7&#xD;

- Added new API method `License::isOfflineActivated`, returns true if license was activated in offline mode.
- Added new API method `License::isActive` for convenience, equivalent to `status() == LicenseStatus::Active`.
- Fixed a few minor bugs, `License::isExpired` now returns correct value for inactive or disabled license.

### July 31, 2019, v 4.4.6&#xD;

- Added ability to control network timeout interval
- Added ability to set up proxy using `ProxySettings`

### July 26, 2019, v 4.4.5&#xD;

- Fixed expiry policy for subscription license type
- Fixed license re-enabling issue
- Fixed missing config.h/config.cpp for Linux and Mac samples
- `LicenseManager::dispose` renamed to `deinitialize`

### July 9, 2019, v 4.4.4&#xD;

- Fixed minor memory leak in ErrorHandler class
- Fixed a few compiler and linker warnings
- Stability and performance improvements

### July 8, 2019, v4.4.3&#xD;

- Added static MD configuration
- Fixed a few memory leaks
- Stability and performance improvements

### June 20, 2019, v4.4.2&#xD;

- Fixed access violation crash when using SDK as a plugin for Unreal Engine
- Fixed Hardware ID issue, now it's accessible for reading
- Build for VC142 (Visual Studio 2019)
- OpenSSL and cUrl updated to latest stable builds
- Stability and performance improvements

### June 12, 2019, v4.4.1&#xD;

- New API method `LicenseManager::dispose`, it helps free up SDK resources on demand
- Stability and performance improvements

### May 11, 2019, v4.3.0&#xD;

- New Hardware ID calculation algorithm, much more faster and secure
- Consumption licensing, new methods `increaseConsumptionCounter`, `totalConsumptions`, `maxConsumptions` and new exception type `NotEnoughConsumptionException`. See sample app for details.
- Fixed bug of handling license check response

### May 8, 2019, Linux v4.2.1&#xD;

- Removed redundant dependencies
- Fixed CMake scripts
- Fixed relative path for shared libs

### April 23, 2019, v4.2.1&#xD;

- Ability to set custom hardware ID
- `LicenseSpringExtendedOptions`, all optional SDK configuration properties now brought together in ExtendedOptions class, see LicenseSpringConfiguration.h for details
- `lib` and `dll` folders changed to `static` and `dynamic` accordingly
- Improved networking and error handling

### April 15, 2019, v4.2.0&#xD;

- License status, `isActive` now replaced with `status` for the License class, for more details see LicenseStatus.h
- Implemented getting of local IP address
- New and faster method of getting OS version info
- Improvements for `LicenseType` class, new comparison operators and constructor

### April 8, 2019, v4.1.2&#xD;

- Separate release for VC140 (Visual Studio 2015)
- Fixed handling of max date time (applicable to validity period of perpetual license or not set maintenance period)
- Fixed project files for the SDK and sample apps
- SDK dependencies (OpenSSL and cURL) updated to latest stable versions
- Added script for building dependencies from sources


[title] Subscription
[path] SDKs/Tutorials/Licensing Scenarios/License Types/

In this guide, we'll delve into the realm of subscription licensing, accompanied by LicenseSpring's powerful SDKs.&#x20;

Whether you're a seasoned developer or just beginning, this tutorial will equip you to seamlessly integrate subscription licenses into your software offerings.

## Prerequisites

1. Completed the [**Getting Started**](docId\:LSFY9tQ3vfq4ROOW9sHkd) Tutorial, including:
   - Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
   - Created a `LicenseID` using either `LicenseID::fromKey` or `LicenseID::fromUser` function, depending on the activation method you prefer.
   - Activated a license of any type.

## Interpreting and Retrieving Validity Period

Similar to time-limited licensing, you gain the ability to set the default validity period for generated license keys.&#x20;

This validity period signifies the duration in days between the initial activation of the license key and its expiration.&#x20;

With subscription licenses, however, there exist getters for the validity period including the grace period.

Just like with time-limited licenses, the SDKs offer the ability to retrieve these fields in local time and UTC:

:::CodeblockTabs
```cpp
tm LicenseSpring::License::validityWithGracePeriod()
tm LicenseSpring::License::validityWithGracePeriodUtc()	
```

```csharp
DateTime LicenseSpring.License.ValidityWithGracePeriod()	
DateTime LicenseSpring.License.ValidityWithGracePeriodUTC()	
```

```python
license.validity_with_grace_period()
```
:::

## Interpreting and Retrieving Grace Period

Grace periods offer you the flexibility to determine a specific timeframe, measured in hours, subsequent to the expiry of the designated validity period.&#x20;

During this defined interval, the license will retain its validity (`isExpired()` status will remain false), ensuring a seamless transition even after the official expiration.

To access the current license's grace period, developers can use the following:

:::CodeblockTabs
```cpp
uint32_t LicenseSpring::License::subscriptionGracePeriod()	
```

```csharp
uint LicenseSpring.License.SubscriptionGracePeriod()	
```

```java
Integer getGracePeriodDays()
```

```swift
// obtain Grace period:
license.gracePeriod
```

```python
license.subscription_grace_period()
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x43;++ and C# grace period retrieval returns the time remaining in **hours**, while the Java implementation returns **days** remaining.
:::

It is also possible to check whether the grace period has started through:

:::CodeblockTabs
```cpp
bool LicenseSpring::License::isSubscriptionGracePeriodStarted()
```

```csharp
bool LicenseSpring.License.IsSubscriptionGracePeriodStarted()	
```

```python
license.is_subscription_grace_period_started()
```
:::

## How to Verify if a License has Expired&#x20;

By employing our system, you can easily determine whether a license has expired or remains valid.

This process empowers you with accurate information to manage software access effectively, ensuring a seamless user experience.

### Utilizing the "isExpired" Method to Check License Expiry

The `isExpired()` method provides an efficient way to check whether a license has reached its expiration date.&#x20;

Our SDKs offer the ability to check the expiration status through the use of the following `License` methods:

:::CodeblockTabs
```cpp
bool LicenseSpring::License::isExpired()
```

```csharp
bool LicenseSpring.License.IsExpired()	
```

```java
boolean isExpired()
```

```swift
license.isExpired
```

```python
license.is_expired()
```
:::

:::hint{type="info"}
**Note:** Our Java SDK's isExpired() method is called on the `LicenseData` object.
:::

### Implementing Local Checks for License Expiry

A local license check involves assessing the validity and expiration status of a software license within the immediate operating environment.&#x20;

By performing checks locally, the software verifies the license's authenticity and expiration status without relying on external connections.

If the local license is expired, the SDKs will throw the following exceptions:

:::CodeblockTabs
```cpp
LicenseStateException
```

```csharp
LicenseExpiredException
```

```java
LicenseExpiredException
```

```python
LicenseStateException
```
:::

See [**License Checks**](docId\:ie-DAh13B4dqxMAQoYgrj) for more information about local license checks.

## Understanding the "Days Remaining" Value

Developers can also access a field within the `License` object that holds the number of days remaining until the license expires.

This number of days can be retrieved using the following methods, in the current time zone and UTC, respectively:

:::CodeblockTabs
```cpp
int LicenseSpring::License::daysRemaining()
int LicenseSpring::License::daysRemainingUtc()
```

```csharp
int LicenseSpring.License.DaysRemaining()	
int LicenseSpring.License.DaysRemainingUTC()	
```

```java
long daysRemaining()
```

```python
license.days_remaining()
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x54;he Java SDK only offers the ability to retrieve the days remaining in the current time zone.
:::


[title] License Checks
[path] SDKs/Tutorials/Best Practices/

License checks have a crucial role in the protection of your application.&#x20;

This guide will explain online and offline license checks, their efficient organization within the application, and the implementation of a grace period.&#x20;

## Prerequisites

Before proceeding, make sure you have completed the [**C++ SDK Configuration and Usage**](docId\:mtXGBTQymb-dOqfxbCqop) or Getting Started Tutorial .Net and accomplished the following steps:

- Initialize **LicenseManager&#x20;**(or **LicenseHandler**) with your configuration using the appropriate settings.
- Activate a license for your application.
- Implement the mechanism to retrieve the current license.

## Local Check

Local check does not require an Internet connection and performs the following actions:

1. Verify if the license is enabled, active, and valid. If the license is not in a valid state, it will raise **LicenseStateException&#x20;**&#x69;n C++ or the following exceptions in .Net:&#x20;
   - **LicenseDeletedException**,&#x20;
   - **LicenseDisabledException**,
   - **TrialLicenseExpiredException**,
   - **LicenseExpiredException**,
   - **LicenseInactiveException**.
2. Confirm if the license belongs to the configured product. If the product code of the license and configuration do not match, it will raise **ProductMismatchException**.
3. Detect cheating with the system clock. If cheating is detected, it will raise **ClockTamperedException&#x20;**(C++) or **DateTimeCheatingException&#x20;**(.Net).
4. Ensure that the license belongs to the device. If the license doesn't belong to the device, it will raise **DeviceNotLicensedException**.
5. If VM detection is enabled, check if the device is a VM and if the license allows virtual machines. If VMs are not allowed, and the application is running on a VM, it will raise **VMIsNotAllowedException**.
6. For floating licenses, verify if the floating timeout has expired. If the timeout is expired, it will raise **FloatingTimeoutExpiredException**.

To perform a local check, call the LocalCheck method:

:::CodeblockTabs
```cpp
auto license = licenseManager->getCurrentLicense();
license->localCheck();
```

```csharp
var license = licenseManager.CurrentLicense();
license.LocalCheck();
```

Swift

```swift
try license.localCheck()
```

```python
manager = LicenseManager(conf)

license = manager.load_license()

license.local_check()
```

```go
	// Go SDK v2
	license_data, check_resp, err := lh.LocalCheck(true)
```

```java
License license = licenseManager.getCurrent();
license.localCheck();
```

```javascript
const license = licenseManager.loadLicense();
license.localCheck().then(response => {
  console.log('ok');
}).catch(error => {
  console.error(error);
});
```
:::

## Online Check

1. Verify if the license is enabled, active, and valid. If the license is not in a valid state, it will raise **LicenseStateException&#x20;**&#x69;n C++ or the following exceptions in .Net:&#x20;
   - **LicenseDeletedException**,&#x20;
   - **LicenseDisabledException**,
   - **TrialLicenseExpiredException**,
   - **LicenseExpiredException**,
   - **LicenseInactiveException**.
2. Synchronize the consumption of consumption licenses and features. If there is not enough consumption left, it will raise **NotEnoughConsumptionException**.
3. Update the license with data from the license server.
4. Retrieve the most recent installation file for the product.
5. Register a floating license. If there are no floating slots available, it will raise **MaxFloatingReachedException**.

It can throw the exceptions related to connection issues: **NetworkException**, **NetworkTimeoutException**, and **LicenseServerException**. You can implement a grace period to allow using the application without connection to the server for a limited period.

To run the online check call Check method:

:::CodeblockTabs
```cpp
license->check();
```

```csharp
license.Check();
```

```java
licenseManager.checkLicense(license);
```

Swift

```swift
try license.fullCheck()
```

```python
license.check()
```

```go
	// Go SDK v2
	license_data, err = lh.CheckLicense(ctx)
```

```javascript
const license = licenseManager.loadLicense();
license.check().then(response => {
  console.log('ok');
}).catch(error => {
  console.error(error);
});
```
:::

## License Check Optimization

License checks can take up to a couple of seconds. It is recommended to run them in a background thread.&#x20;

Perform local checks on every application startup to ensure the user has a valid license.&#x20;

However, since calling an online check at every start of the application is redundant, we recommend performing it every few days, using the last check date value saved in the license.&#x20;

:::CodeblockTabs
```cpp
if( license->daysPassedSinceLastCheck() >= 3 )
  license->check();
```

```csharp
if( license.DaysPassedSinceLastCheck() >= 3 )
  license.Check();
```

Swift

```swift
if Date().timeIntervalSince(linense.lastSyncDate) > 24 * 60 * 60 { // 1 day.
    try license.fullCheck()
}
```

```python
if license.days_since_last_check() >= 3:
    license.check()
```

```java
long daysPassedSinceLastCheck = license.daysPassedSinceLastCheck();
if (daysPassedSinceLastCheck > 3) {
    licenseManager.checkLicense(license);
}
```

```javascript
const license = licenseManager.loadLicense();
if (license.daysSinceLastCheck > 3) {
  license.check().then(response => {
    console.log('ok');
  }).catch(error => {
    console.error(error);
  });
}
```
:::

If you need to synchronize consumption more often, you can use SyncConsumption and SyncFeatureConsumption methods.

## Grace Period

A grace period can be helpful when you don't want to restrict application usage due to online check failures caused by the lack of an internet connection or internal LicenseSpring server issues.&#x20;

To implement this, define how long it is allowed to use the application without connecting to the server and handle network exceptions accordingly.

:::CodeblockTabs
```cpp
auto allowedPeriodWithoutCheck = 7;//allow a week of usage without connection
try
{
  license->check();
  return true;//continue after successful check
}
catch( const LicenseSpringException& ex )
{
  auto code = ex.getCode();
  if( code == eNoInternetError || code == eNetworkTimeoutError || code == eServerError )
    return license->daysPassedSinceLastCheck() < allowedPeriodWithoutCheck;
    //stop if the app is offline or cannot connect to the server longer than the allowed period
  return false;//stop in case of other exceptions
}
```

```csharp
var allowedPeriodWithoutCheck = 7;//allow a week of usage without connection
try
{
  license.Check();
  return true;//continue after successful check
}
catch( LicenseSpringException ex )
{
  if( ex is NetworkException || ex is LicenseServerException )
    return license.DaysPassedSinceLastCheck() < allowedPeriodWithoutCheck;
    //stop if the app is offline or cannot connect to the server longer than the allowed period
  return false;//stop in case of other exceptions
}
```

```java
LicenseSpringConfiguration config = 
    LicenseSpringConfiguration.builder()
        .gracePeriodDays(3) // 3 days of grace period
        .build();
```

```javascript
const licenseManager = new LicenseManager({
  apiPath: 'string',
  publicKey: 'string',
  appName: 'string',
  appVersion: 'string',
  filePath: 'string',
  filename: 'string',
  fileKey: 'string',
  apiKey: 'string',
  sharedKey: 'string',
  productCode: 'string',
  gracePeriod: 3
});
```
:::

The grace period feature is available in **C++ SDK** from **v7.26.0&#x20;**&#x61;nd in **.Net SDK&#x20;**&#x66;rom **v7.22.0**. It covers `License::check`, `License::syncConsumption`,` License::syncFeatureConsumption`, and `License::sendDeviceVariables` methods.&#x20;

:::hint{type="warning"}
Do not confuse grace period and subscription grace period. To learn more about the subscription grace period, see: [**Subscription**](docId\:O79gCxoa72yQlYJl3BbHq)
:::

By default grace period is **48 hours**. You can set another value using:

:::CodeblockTabs
```cpp
LicenseSpring::ExtendedOptions options;
options.setGracePeriod( 24 );//set 24 hours
options.setGracePeriod( 0 );//disable grace period
```

```csharp
var options = new LicenseSpring.ExtendedOptions();
options.GracePeriod = 24;//set 24 hours
options.GracePeriod = 0;//disable grace period
```

```python
conf = Configuration(product="your_product_key",api_key="your_api_key",
                   shared_key="your_shared_key",file_key=key,file_iv=iv,
                   grace_period_conf=24)
       
```

```go
// Go SDK v2
lm_config := license_manager.LicenseManagerBasicConfiguration{
				OAuth:             false,
				ApiKey:            "your-api-key",
				SharedKey:         "your-shared-key",
				ProductCode:       "your-product-code",
				AuthData:          auth.FromKey("LICENSE-KEY"),
			}

lm, _ := license_manager.NewLicenseManager(
    lm_config,
    license_manager.WithGracePeriod(24),
)

cfg.Manager = lm

lh, _ := license_handler.NewLicenseHandler(cfg)
```

```java
// gracePeriodDays default value is 0
LicenseSpringConfiguration config = 
    LicenseSpringConfiguration.builder()
        .gracePeriodDays(3) // 3 days of grace period
        .build();
```

```javascript
const licenseManager = new LicenseManager({
  apiPath: 'string',
  publicKey: 'string',
  appName: 'string',
  appVersion: 'string',
  filePath: 'string',
  filename: 'string',
  fileKey: 'string',
  apiKey: 'string',
  sharedKey: 'string',
  productCode: 'string',
  gracePeriod: 3
});
```
:::

The **License&#x20;**&#x63;lass has methods to check if the grace period started and get the grace period end date:

:::CodeblockTabs
```cpp
license->check();
if( license->isGracePeriodStarted() )
    std::cout << "Grace period started. " << license->gracePeriodHoursRemaining() << " hours till the end of grace period.";
```

```csharp
license.Check();
if( license.IsGracePeriodStarted() )
    Console.WriteLine( "Grace period started.{0} hours till the end of grace period.", license.GracePeriodHoursRemaining() );
```

```python
license.check()
if license.is_grace_period_started():
    print("Grace period hours remaining:",license.grace_period_hours_remaining())
```

```go
// Go SDK v2
if license_data.IsGracePeriodStarted():
    fmt.Println("Grace period started at: ",license_data.GracePeriodStartDate)
```

```java
LicenseSpringConfiguration config = 
    LicenseSpringConfiguration.builder()
        .gracePeriodDays(3) // 3 days of grace period
        .build();
   
// Grace period: ignore license check failures for 3 days after the last successful check     
long daysPassedSinceLastCheck = license.daysPassedSinceLastCheck();
```
:::

The grace period starts when one of the covered requests fails and resets after a successful request. The license is currently in its grace period, and either it is a **non-floating license**, or it is a **floating license&#x20;**&#x77;ith at least one hour remaining before expiration.&#x20;


[title] Air-Gapped Licensing
[path] SDKs/Tutorials/Licensing Scenarios/

[**Air gap licensing**](https://docs.licensespring.com/license-entitlements/activation-types/air-gapped) is a useful feature for isolated environments. The concept is similar to offline license management.&#x20;

The main difference is that in regular offline activation we exchange files and and in air-gapped environments we cannot use files so we have to rely on exchanging strings.

In this guide you will find the instructions for implementing air-gap licensing using LicenseSpring SDK.

## Prerequisites

1. Completed the [**Getting Started**](docId\:LSFY9tQ3vfq4ROOW9sHkd) Tutorial, specifically:
   - Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
   - Activated a key-based license of any type.

## Air-Gap Configuration

The air-gap public key is necessary to verify the confirmation code obtained from the air-gap activation portal. The public key can be found on the LicenseSpring portal under Settings->Keys.&#x20;

::Image[]{src="https://lh3.googleusercontent.com/u_fCrQWPEI-m1MphS-j7BBxMj9YMKP_NhJ4xdZdv7MNN2kckREYwPX74C-znia3gEhY2JHif_RrgPuP_i9O4i9bYgUXV-ObctBwXhHar1-OCpojiHxT6dpBXwDRvM9k_c51plU0VrHNcsITAXYoN9Q" signedSrc="https://lh3.googleusercontent.com/u_fCrQWPEI-m1MphS-j7BBxMj9YMKP_NhJ4xdZdv7MNN2kckREYwPX74C-znia3gEhY2JHif_RrgPuP_i9O4i9bYgUXV-ObctBwXhHar1-OCpojiHxT6dpBXwDRvM9k_c51plU0VrHNcsITAXYoN9Q" size="78" width="1269" height="666" position="center" caption}

If the air-gap public key is not set correctly in the configuration, the activation process will raise an **AirGapActivationException&#x20;**&#x77;ith the message "Confirmation code is invalid."

To set the air-gap public key in the configuration use:

:::CodeblockTabs
```cpp
Configuration::setAirGapPublicKey("your_air_gap_public_key");
```

```csharp
Configuration.AirGapPublicKey = "your_air_gap_public_key";
```

```swift
configuration.airgapKey = "your_air_gap_public_key"
```

```python
from licensespring.licensefile.config import Configuration

conf = Configuration(product="your_product_key",api_key="your_api_key",
                   shared_key="your_shared_key",file_key=key,file_iv=iv,
                   is_guard_file_enabled=True,
                   air_gap_public_key="your_air_gap_public_key")
```

```java
LicenseSpringConfiguration config = LicenseSpringConfiguration.builder()
  .airGappedPublicKey("<AIR-GAP-PUBLIC-KEY>")
  .build();
```
:::

To secure the air-gap activation, make sure that guard file option is not set to false. This feature is enabled by default and ensures that the license will not be activated multiple times with the same data, enhancing security and reliability. 

:::CodeblockTabs
```cpp
ExtendedOptions::enableGuardFile(true);
```

```csharp
ExtendedOptions.ProtectOfflineActivation = true;
```
:::

## License Activation

To activate a license, follow these steps:

Open the air-gap activation [**portal&#x20;**](https://airgap.licensespring.com/)and enter the license key. It will display the key and initialization code.&#x20;

::Image[]{src="https://lh3.googleusercontent.com/puNVihyrPdb3LH0ZSlrrmm1zoCFK6RVY8Cz-ol6VGHCx5kv1j4BjF2VX6dyDppxYT19I6I7qpidyVXnl_bUCrQHGv4iIuDIFoFRgRiCu_ek-fga3melSvLpa1COurqpHwE1JAaf3PR057fxrUqkoLw" signedSrc="https://lh3.googleusercontent.com/puNVihyrPdb3LH0ZSlrrmm1zoCFK6RVY8Cz-ol6VGHCx5kv1j4BjF2VX6dyDppxYT19I6I7qpidyVXnl_bUCrQHGv4iIuDIFoFRgRiCu_ek-fga3melSvLpa1COurqpHwE1JAaf3PR057fxrUqkoLw" size="58" width="775" height="421" position="center" caption}

::Image[]{src="https://lh4.googleusercontent.com/p40lam5CZmpMHrZGvDMK8cy8TPYATezVPWZp0B_Ld5QAel0nkS4nHnB8o8__N0-jMxaq7vqS45kiyCvu960z1izRGH70cRwwBVtLpyIMSC1B2cSPpeqvXXFP6wWeCV8LxP7jFkKAJSAPl3ax_3LXTQ" signedSrc="https://lh4.googleusercontent.com/p40lam5CZmpMHrZGvDMK8cy8TPYATezVPWZp0B_Ld5QAel0nkS4nHnB8o8__N0-jMxaq7vqS45kiyCvu960z1izRGH70cRwwBVtLpyIMSC1B2cSPpeqvXXFP6wWeCV8LxP7jFkKAJSAPl3ax_3LXTQ" size="58" width="754" height="757" position="center" caption}

Use the **GetAirGapActivationCode&#x20;**&#x6D;ethod to get the activation code, passing the key and initialization code as parameters. Additionally, retrieve the hardware ID from the SDK configuration.

:::CodeblockTabs
```cpp
auto activationCode =  licenseManager->getAirGapActivationCode( initCode, licenseKey );
auto hardwareId = configuration->getHardwareID();
```

```csharp
var activationCode = licenseManager.GetAirGapActivationCode( initCode, licenseKey );
var hardwareId = configuration.HardwareID;
```

```swift
let activationCode = try manager.generateAirgapActivationCode(
    initializationCode: initCode,
    licenseKey: licenseKey
)
let hardwareID = configuration.hardwareID
```

```python
from licensespring.hardware import HardwareIdProvider
from licensespring.licensefile.license_manager import LicenseManager

initialization_code = "Q/MWfwp1NWAYARl8Q7KSo5Cg2YKqS2QLlnQ3nEeSBsk="
license_key = "UFF3-E9GA-VUJQ-GMLK"

manager = LicenseManager(conf)
activation_code = manager.get_air_gap_activation_code(initialization_code=initialization_code, license_key=license_key)

print("Activation code:",activation_code)
print("hardware id:",HardwareIdProvider().get_id())
```

```go
// Go SDK v2
activationCode, err := lh.GetAirGapActivationCode(initializationCode, licenseKey)
```
:::

Enter the license key, hardware ID, and activation code in the activation portal. It will provide the policy ID and confirmation code and make the license active on the platform.

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/0W4PCgPxI0M0-m-Tyr9Xz_image.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/0W4PCgPxI0M0-m-Tyr9Xz_image.png" size="58" width="766" height="673" position="center" caption}

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/iWJIdAzkrjXBXC9InsqSL_airgapcode.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/iWJIdAzkrjXBXC9InsqSL_airgapcode.png" size="58" width="765" height="1018" position="center" caption}

Download the policy file from the licensing platform.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/IbJJcpN1f6KdYlxaA9Zwz_screenshotpolicyfile.png)

Use the **ActivateAirGapLicense&#x20;**&#x6D;ethod, passing the policy ID, key, confirmation code, and the path to the policy file or the location of multiple policy files. This will activate the license on the device.

:::CodeblockTabs
```cpp
auto license = licenseManager->activateAirGapLicense( "confirmation_code", L"policy/file/path", "license_key", policyId.toUInt() );
```

```csharp
var license = licenseManager.ActivateAirGapLicense( "confirmation_code", "policy/file/path", "license_key", UInt32.Parse( "policy_id" ) );
```

```swift
try manager.verifyAirgapConfirmationCode(
    confirmationCode: "confirm_code",
    licenseKey: licenseKey,
    policyID: policyID
)
    
let license = try manager.activateLicense(
    airgapPolicyFile: policyFileLocation,
    licenseKey: licenseKey,
    policyID: policyID
)
```

```python
confirmation = "ERbQBuE8giIjqMPj972Skipehqn0szQ8TH56INyo3OdtMHO1SuTVsoCOSnJWB6rml98PJ6SjybTPymOVZTG4hQ=="
policy_id = "998"
license_key = "UFF3-E9GA-VUJQ-GMLK"
policy_path = "path_to_air_lic"

manager = LicenseManager(conf)
license = manager.activate_air_gap_license(
                confirmation_code=confirmation, policy_path=policy_path, license_key=license_key, policy_id=policy_id
            )
```

```go
// Go SDK v2
ld, err = lh.ActivateAirGapLicense(confirmationCode, policyPath, licenseKey, policyId)
```
:::

## Air-Gap license fields

License data contains the information if the license was activated using air-gap approach and the license policy id, 

To get the corresponding fields use:

:::CodeblockTabs
```cpp
bool isAirGapped = license->isAirGapped();
std::string policyId = license->policyId();
```

```csharp
bool isAirGapped = license.IsAirGapped;
string policyId = license.PolicyId;
```

```swift
license.isAirGapActivated
```

```python
print("is air gapped:",license.is_air_gapped())
print("policy id:",license.policy_id())
```
:::

## License deactivation

The air-gap deactivation process is similar to the air-gap activation. It contains the following steps:

Open the air-gap activation [**portal&#x20;**](https://airgap.licensespring.com/)and switch to license deactivation. Enter the license key, it will display the key and initialization code.&#x20;

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Ph8lc4bjUzHEBwgfWUKas_image.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Ph8lc4bjUzHEBwgfWUKas_image.png" size="58" width="762" height="412" position="center" caption}

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ovY2BTHGZnKy40zSQtAqL_screenshotair-gapdeactivate.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ovY2BTHGZnKy40zSQtAqL_screenshotair-gapdeactivate.png" size="58" width="768" height="772" position="center" caption}

Use the **GetAirGapDeactivationCode&#x20;**&#x6D;ethod to get the deactivation code, passing the key and initialization code as parameters. Additionally, retrieve the hardware ID from the SDK configuration.

:::CodeblockTabs
```cpp
auto deactivationCode =  licenseManager->getAirGapDeactivationCode( initCode, licenseKey );
auto hardwareId = configuration->getHardwareID();
```

```csharp
var deactivationCode = licenseManager.GetAirGapDeactivationCode( initCode, licenseKey );
var hardwareId = configuration.HardwareID;
```

```python
deactivation_code = license.get_deactivation_code(initialization_code)

print("Deactivation code:",deactivation_code)
print("hardware id:",HardwareIdProvider().get_id())
```
:::

Enter the license key, hardware ID, and deactivation code in the activation portal. It will provide the confirmation code and make the license inactive on the platform.

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/_hr_auoZbOhCX8UV7qXPd_image.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/_hr_auoZbOhCX8UV7qXPd_image.png" size="58" width="763" height="673" position="center" caption}

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/gXK6XrVp4yFiizDCrYujN_deactivation.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/gXK6XrVp4yFiizDCrYujN_deactivation.png" size="58" width="769" height="1020" position="center" caption}

Use the **DectivateAirGapLicense&#x20;**&#x6D;ethod, passing the confirmation code. This will deactivate the license on the device and remove the local license file.

:::CodeblockTabs
```cpp
license->deactivateAirGap( "confirmation_code" );
```

```csharp
license.DeactivateAirGap( "confirmation_code" );
```

```python
confirmation_code="your_confirmation_code"
license.deactivate_air_gap(confirmation_code)
```
:::

## Errors

During air-gap activation, various exceptions may occur, including those encountered during regular activation. Additionally, in .NET, not all versions are supported. In such cases, a **LicenseSpringException&#x20;**&#x77;ith the message "Air gap feature is not supported on .NET Framework 3.5-4.6" may be thrown.&#x20;

**AirGapActivationException&#x20;**&#x63;an be thrown during license activation and deactivation in case confirmation code verification failed.

[title] nodeJS SDK
[path] SDKs/Tutorials/Getting Started/

## About

This package implements LicenseSpring SDK functionality for Javascript and Typescript.

## Installation

The package is published on npmjs.com and can be installed as follows:

`npm i --save @licensespring/node-sdk`

## Interface

The SDK provides several classes which are used to interface with LicensenSpring services as well as functionality for local license files:

### LicenseAPI

This is a wrapper class for interacting with the License API. It provides all the API endpoints as class methods, provides input validation and response signature checks. If you prefer to implement your own logic for working with LicenseSpring data, this class contains all the necessary functionality.

```javascript
const { LicenseAPI } = require('@licensespring/node-sdk');

const licenseAPI = new LicenseAPI({
  apiKey: '12345678-4bfe-4e3a-8737-757004d6294c',
  sharedKey: 'eYuHrlajvIVTiSFIXpxpKhw78f4Ewy-00-12345678',
  appName: 'js-sdk-test-1',
  appVersion: '0.0.1',
});

const licenseActivation = await licenseAPI.activateLicense({ license_key: 'string', product: 'string', hardware_id: 'string' });

const bundleActivation = await licenseAPI.activateBundle({ license_key: 'string', product: 'string', hardware_id: 'string' });

const licenseCheck = await licenseAPI.checkLicense({ license_key: 'string', product: 'string', hardware_id: 'string' });

const bundleCheck = await licenseAPI.checkBundle({ license_key: 'string', product: 'string', hardware_id: 'string' });

const addConsumption = await licenseAPI.addConsumption({ license_key: 'string', product: 'string', hardware_id: 'string', consumptions: 10 });

const addFeatureConsumption = await licenseAPI.addFeatureConsumption({ license_key: 'string', product: 'string', hardware_id: 'string', feature: 'string', consumptions: 10 });

const licenseFeatureCheck = await licenseAPI.checkLicenseFeature({ license_key: 'string', product: 'string', hardware_id: 'string', feature: 'string' });

const trackDeviceVariables = await licenseAPI.trackDeviceVariables({ license_key: 'string', product: 'string', hardware_id: 'string', variables: { key1: 'value1' } });

const getDeviceVariables = await licenseAPI.getDeviceVariables({ license_key: 'string', product: 'string', hardware_id: 'string' });

const licenseDeactivation = await licenseAPI.deactivateLicense({ license_key: 'string', product: 'string', hardware_id: 'string' });

const bundleDeactivation = await licenseAPI.deactivateBundle({ license_key: 'string', product: 'string', hardware_id: 'string' });

/* NOTE: the hardware_id value can be either generated by your app 
 * (eg. using custom-made hardware fingerprinting logic) or you
 * can use the hardware ID module exposed by this class: 
 */
 const hardwareID = licenseAPI.getHardwareID();
```

For a more detailed overview of this class see: [**License API**](docId\:Rw7pVb8trym2nQLrPO_Mg)&#x20;

### LicenseManager

This class extends the functionality provided by the LicenseAPI class and provides methods for managing licenses. In addition to encapsulating API calls, this class reads and writes local license files and handles hardware ID generation internally.

```javascript
const { LicenseAPI } = require('@licensespring/node-sdk');

const licenseManager = new LicenseManager({
  apiKey: '12345678-4bfe-4e3a-8737-757004d6294c',
  sharedKey: 'eYuHrlajvIVTiSFIXpxpKhw78f4Ewy-00-12345678',
  appName: 'js-sdk-test-1',
  appVersion: '0.0.1',
  productCode: 'myproduct1', // NOTE: each LicenseManager instance is attached to a specific product
});

const licenseActivation = await licenseManager.activateLicense({ license_key: 'string' });

const licenseCheck = await licenseManager.checkLicense({ license_key: 'string' });

const addConsumption = await licenseManager.addConsumption({ license_key: 'string', consumptions: 10 });

const addFeatureConsumption = await licenseManager.addFeatureConsumption({ license_key: 'string', feature: 'string', consumptions: 10 });

const licenseFeatureCheck = await licenseManager.checkLicenseFeature({ license_key: 'string', feature: 'string' });

const trackDeviceVariables = await licenseManager.trackDeviceVariables({ license_key: 'string', variables: { key1: 'value1' } });

const getDeviceVariables = await licenseManager.getDeviceVariables({ license_key: 'string' });

const licenseDeactivation = await licenseManager.deactivateLicense({ license_key: 'string' });

// this loads the license object from the local license file;
const license = licenseManager.loadLicense();

const localCheck = await license.localCheck();

license.addLocalConsumption(10);

license.addLocalFeatureConsumption('feature1', 5);
```

For a more detailed overview of this class see: [**License Manager**](docId\:TbXzhRg7EYXTCwbt45Lsh)&#x20;

### BundleManager

This class extends the functionality provided by the LicenseAPI class and provides methods for managing license bundles. The behaviour of this class is similar to LicenseManager, the only difference being that this class is used for license **bundles**, as opposed to single licenses.

For a more detailed overview of this class see: [**Bundle Manager**](docId\:n-5C4U-vxLWkD-hxiIlhY)&#x20;

### LicenseFile

This class encapsulates the local license file produced by the LicenseManager or BundleManager. This file is used by client applications to track the license state on local storage.

For a more detailed overview of this class see: [**License File**](docId\:kVSI-spAR2AYsn8JvqZtt)&#x20;


[title] License Data
[path] SDKs/Tutorials/Licensing Scenarios/License Types/

Whether you are a developer seeking to integrate licensing features into your product or a system administrator responsible for overseeing licenses, understanding how to access license data is crucial for effective licensing management.

In LicenceSpring, licenses are equipped with numerous fields, encompassing essential information such as status, maintenance period, start date, and more.&#x20;

In this tutorial, we will delve into the process of accessing these fields and comprehending their significance.&#x20;

## Prerequisites

1. Completed the [**Getting Started**](docId\:LSFY9tQ3vfq4ROOW9sHkd) Tutorial, specifically:
   - Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
   - Created a `LicenseID` using either `LicenseID::fromKey` or `LicenseID::fromUser` function, depending on the activation method you prefer.
   - Activated a license of any type.

## License ID&#x20;

LicenseID is a fundamental component of LicenceSpring's licensing infrastructure, serving as a crucial license identifier object.&#x20;

It acts as a unique and immutable identifier assigned to each individual license within the system.

LicenseID can be accessed using the following getters on the `License` object:

:::CodeblockTabs
```cpp
const LicenseID& LicenseSpring::License::id()	
```

```csharp
LicenseID LicenseSpring.License.Id()	
```

```swift
// key-based:
license.licenseKey

// user-based:
license.user
```

```java
LicenseIdentity identity = license.getIdentity();
```
:::

## License Status&#x20;

License status is a critical attribute within LicenceSpring's licensing framework, representing the current state of a license.&#x20;

As a string value, it can take on four distinct values: 'Active', 'Disabled', 'Expired', or 'Inactive'.

Developers can access license status in the SDKs through:

:::CodeblockTabs
```cpp
std::string LicenseSpring::License::status()
```

```csharp
LicenseStatus LicenseSpring.License.Status()	
```

```swift
license.state
```

```python
license.check_license_status()
```
:::

For more information about the different statuses, see [**License Types**](docId\:xHxttCVj7gs6qeAqu7Cua).

You can also check for active, valid, enabled, and expired licenses using `isActive`, `isValid`, `isEnabled`, and `isExpired` methods respectively.&#x20;

## Maintenance Period

A maintenance period refers to a specific duration during which software vendors or service providers offer ongoing support, updates, and access to new versions or features for their products or services.&#x20;

See [**Maintenance Period**](docId\:Modljq4cp5uboMxrRQxbK) for more information about implementing a maintenance period.

Developers have multiple fields to utilize when it comes to maintenance periods, starting with the getter for license maintenance period in local time or UTC. These are shown below:

:::CodeblockTabs
```cpp
//Local time
tm LicenseSpring::License::maintenancePeriod()	
//UTC
tm LicenseSpring::License::maintenancePeriodUtc()
```

```csharp
//Local time
DateTime LicenseSpring.License.MaintenancePeriod()	
//UTC
DateTime LicenseSpring.License.MaintenancePeriodUTC()	
```

```swift
license.maintenancePeriod
```

```python
license.maintenance_period()
```

```java
  ZonedDateTime maintenancePeriod = license.getMaintenancePeriod();
```
:::

It is also possible to check if the maintenance period is expired, using the Boolean checker:

:::CodeblockTabs
```cpp
bool LicenseSpring::License::isMaintenancePeriodExpired()	
```

```csharp
bool LicenseSpring.License.IsMaintenancePeriodExpired()	
```

```swift
license.isMaintenancePeriodExpired
```

```python
license.is_maintence_period_expired()
```
:::

Finally, the LicenseSpring SDKs offer the ability to return the number of days remaining until the end of the maintenace period:

:::CodeblockTabs
```cpp
int LicenseSpring::License::maintenanceDaysRemaining()
```

```csharp
int LicenseSpring.License.MaintenanceDaysRemaining()
```

```python
license.maintenance_days_remaining()
```
:::

## Start Date

Licenses have an optional start date field, defining the first activation date for added flexibility.&#x20;

This allows customers to activate licenses when needed, aligning with specific timelines and project requirements.&#x20;

It also enables software vendors to generate pre-sales and plan product launches efficiently.

The start date of a license can be accessed by using:

:::CodeblockTabs
```cpp
std::string & LicenseSpring::License::startDate()	
```

```csharp
DateTime LicenseSpring.License.StartDate()	
```

```swift
license.startDate // Date?
```

```python
license.start_date()
```
:::

:::hint{type="danger"}
**CannotBeActivatedNowException** will be thrown if start date field is set for the license and current date is behind start date.
:::

## Last Check:

The license last check date in local time is provided as a time structure, indicating the most recent date and time when the license was last checked on the user's system, adjusted to either the local time zone or UTC.&#x20;

These getters for the date and time of the last check are:

:::CodeblockTabs
```cpp
//Local time
tm LicenseSpring::License::lastCheckDate()
//UTC
tm LicenseSpring::License::lastCheckDateUtc()
```

```csharp
//Local time
DateTime LicenseSpring.License.LastCheckDate()	
//UTC
DateTime LicenseSpring.License.LastCheckDateUTC()	
```

```swift
license.lastSyncDate
```

```python
license.last_check()
```

```java
license.getLastCheck();
```
:::

It is also possible to retrieve the number of days since the last check:

:::CodeblockTabs
```cpp
int LicenseSpring::License::daysPassedSinceLastCheck()	
```

```csharp
int LicenseSpring.License.DaysPassedSinceLastCheck()
```

```python
license.days_since_last_check()
```

```java
license.daysPassedSinceLastCheck();
```
:::

## Activation Count:

Tracking current activations and maximum activations is vital for effective license management.&#x20;

The current activations offer real-time insights into usage trends, aiding vendors in decision-making, while the maximum activations set crucial limits, preventing unauthorized use and ensuring compliance. The getters used to access these values are shown below:

:::CodeblockTabs
```cpp
//Number of current activations
uint32_t LicenseSpring::License::timesActivated()
//Maximum activations
uint32_t LicenseSpring::License::maxActivations()	
```

```csharp
//Number of current activations
uint LicenseSpring.License.TimesActivated()	
//Maximum activations
uint LicenseSpring.License.MaxActivations()	
```

```swift
license.timesActivated
license.maxActivations
```

```python
license.max_activations()
```

```java
int maxActivations = license.getMaxActivations();
```
:::

This data empowers both vendors and users to optimize resource allocation and maintain a harmonious licensing ecosystem.

:::hint{type="danger"}
**LicenseNoAvailableActivationsException** thrown when license has already been activated maximum number of times.
:::

## License Transfers

License transfer refers to the process of moving a software license from one device to another.&#x20;

In such cases, the activation of the license on the new device is counted as an activation event.&#x20;

This means that when a license is transferred to a different device, it is considered as if it were newly activated on that device.&#x20;

Developers can access the current transfer count of a license by using:

:::CodeblockTabs
```cpp
uint32_t LicenseSpring::License::transferCount()
```

```csharp
uint LicenseSpring.License.TransferCount()	
```

```swift
license.transferCount
```

```python
license.transfer_count()
```
:::

To check the amount of allowed transfers on a license:

:::CodeblockTabs
```cpp
int32_t LicenseSpring::License::transferLimit()
bool LicenseSpring::License::isDeviceTransferAllowed()
bool LicenseSpring::License::isDeviceTransferLimited()
```

```python
license.is_device_transfer_limited()
license.is_device_transfer_allowed()
```
:::

## License Owner

The license owner refers to the individual or organization associated with a specific software license.&#x20;

This information provides essential details about the entity that holds the rights and permissions to use the licensed product or service.&#x20;

The license owner can be retrieved through the SDK with:

:::CodeblockTabs
```cpp
Customer LicenseSpring::License::owner()
```

```csharp
Customer LicenseSpring.License.Owner()
```

```swift
license.customer // Customer
```

```java
LicenseData data = license.getData();
Customer customer = data.getCustomer();
```
:::


[title] .NET/C#
[path] SDKs/Tutorials/Getting Started/

Incorporating software licensing into your .NET/C# application becomes a simple process using the LicenseSpring SDK.

All you need to do is import our SDK into your project, and you're all set to start developing.&#x20;

If you can't locate the binaries suitable for your particular environment, no need for concern. Just [**submit a support ticket**](https://licensespring.zendesk.com/hc/en-us/requests/new), and we'll gladly compile them for you. Our committed support team is available to guide you through each phase.

So, let's commence the journey and unleash the complete capabilities of licensing and entitlement management within your .NET/C# application.

[title] Java Advanced Usage
[path] SDKs/Java SDK/

## Detecting Virtual Machines

In case your `License` is using the `Prevent virtual machine` feature, the Java SDK will try to detect a Virtual Machine (VM) by comparing common VM signatures in hardware components of a node (computer).

In case any of the mentioned components match a VM component signature and the feature is active, the License activation will fail!

:::hint{type="info"}
If you come across a Virtual Machine that's not properly detected, [**please submit a ticket&#x20;**](https://licensespring.zendesk.com/hc/en-us/requests/new)with information about the VM used so we can add it to the detector.
:::

### Virtual Machines Currently Detected Using the Java SDK

The detection process compares the hardware signatures of the current node (computer) against a list of the following known VM signatures:

:::BlockQuote
bhyve
Docker Container
FreeBSD Jail
KVM
LXC
Lguest
Linux-VServer
Microsoft Hyper-V
OpenVZ
Parallels
Project ACRN
QEMU
QNX Hypervisor
VMware
Windows Virtual PC
Xen/Oracle
Virtual Iron
VirtualBox
:::

## Multiple Licenses on Same Device in LicenseClient

By default, the `LicenseManager` is used as a singleton - but if there is a need for multiple `LicenseManagers`, each with it's own configuration - you can use the `LicenseManagerFactory` to create additional managers or use the singleton like before.

```java

// creates a new LicenseManager object, there can be multiple ones using this method
LicenseManager multipleLicences = LicenseManagerFactory.createLicenseManager();

// uses the singleton variant, only 1 manager can be initialized using this method
LicesneManager singleton = LicenseManagerFactory.getLicenseManager();
```

## Custom License Storage in License Client

By default the license is stored on the local disk - encrypted when storing. The location of the license can be changed via the `Configuration` object. A custom `LicenseRepository` can also be implemented, see sample below:

```java

// another way to initialize the manager
// is to pass it an additional field which is
// your own implementation of the LicenseRepository interface
public class MyLicenseRepository implements LicenseRepository {
  	void save(License license) {
      	// save the license
    }
 	void delete() {
      	// delete the license 
    }
  	License load() {
		// load the license
    }
  	// add any additional methods you need
}

try {
	licenseManager.initialize(configuration, new MyLicenseRepository());
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}
```

## Implementing Your Own LicenseSpring using LicenseSpring Core

This is possible to do, where you get to reuse most of the DTOs and authorization that was built. Feel free to contact us, if you require help of implementing your own SDK, with the boilerplate and authorization layers already finished.

## Forward Proxy

The [**Java License Client**](docId\:UwqR7jQG01pCftet8Iao0), [**Floating Client**](docId:85OZDMi_CEEi_i5T6ldh7), [**Proxy Floating**](docId:-r7g0sf5yq0jYyawahn_9) and [**Management SDK**](docId\:oqeHm3FlI2mJ-0AQ8u724) - all have support for setting up a forward proxy. Just set the `proxyPort` and `proxyHost` fields in any of the configurations to use a forward proxy for your application. You can set just the `proxyPort` field - this will automatically use "localhost" as the `proxyHost`.

There is also support for Basic Auth, by setting the `proxyUser` and `proxyPass` fields in any of the configurations.

Here is an example setup for the `License Client` module:

```java
LicenseSpringConfiguration configuration = LicenseSpringConfiguration.builder()
                        .apiKey("api_key")
                        .productCode("product_code")
                        .sharedKey("shared-key")
						.proxyHost("192.168.0.254")
                        .proxyPort(1337)
  						.proxyUser("SampleUser")
						.proxyPass("SamplePass")
                        .build();
```

## Disable SSL

:::hint{type="info"}
**disableSsl()&#x20;**&#x73;till uses ssl traffic, it just **trusts all certificates**
:::



In rare cases, some clients using a forward proxy cannot verify the public certificate of LicenseSpring servers. For these cases, there is an option in the the `License Client`, `Floating Client` and `Management SDK` called `disableSsl`

Here is an example setup for the `License Client` module:

```java
LicenseSpringConfiguration configuration = LicenseSpringConfiguration.builder()
                        .apiKey("api_key")
                        .productCode("product_code")
                        .sharedKey("shared-key")
						.disableSsl(true)
                        .build();
```

## Shutdown Scheduled Executors

License Client (`LicenseManager`), Floating Client (`FloatingLicenseService`) and Proxy Floating Client (`ProxyFloatingService`) have the method `shutdownScheduler()`, which calls `shutdownNow()` for their scheduled executors. The executors are used in making periodic checks (if it's enabled) and in some cases will leave threads running indefinitely - when no shutdown signal is received.

## Offline Mode Toggle

LicenseManager has the option to dinamically trigger offline/online mode with the method setOfflineMode(boolean) - mentioned here: [**https://docs.licensespring.com/sdks/java/modules/license-client#NzxDY**](https://docs.licensespring.com/sdks/java/modules/license-client#NzxDY)

For detecting if the user has access to internet: The connection type is "com.licensespring.model.exceptions.infrastructure.ConnectionException", with the message: "[**api.licensespring.com**](http://api.licensespring.com/): nodename nor servname provided, or not known" or message "timeout" - depending if the internet was available at some point during app running ("timeout" message if internet was available at some point and later disabled)

## Custom Service URL

License Client and Floating client can have alternate serviceUrls (when base domain is not [**http://licensespring.com/**](http://licensespring.com/))
to override, use the `serviceURL` and `serviceUrlCertPath` configuration params
the certificate needs to be a `.pem` file (on disk or a resource)


[title] .NET/C# SDK
[path] SDKs/

## ZIP File Includes:

- SDK: .NET versions 3.5; 4.0; 4.5; 4.5.1; 4.5.2; 4.6; 4.6.1; 4.6.2; 4.7; 4.7.1; 4.7.2; 4.8; .NET Standard 2.0, Xamarin.Forms, .Net6
- Code Samples for Console app, WinForm, VB.Net and VBA, Xamarin.Forms Android and iOS
- Documentation
- Release notes

[**LicenseSpring.NetSDK-v7.41.0.zip**](https://sdk.licensespring.com/.NET/v7.41.0/LicenseSpring.NetSDK-v7.41.0.zip)

**Note:**

You may download the .NET SDK via NuGet from here: [**https://www.nuget.org/packages/LicenseSpring.NetSDK/**](https://www.nuget.org/packages/LicenseSpring.NetSDK/)

**Supported versions:&#x20;**

- net5.0, net6.0, net7.0, net8.0
- netstandard2.0, netstandard2.1
- net45, net451, net452, net46, net461, net462, net47, net471, net472, net48

## Release Notes

### February 13, 2026, v7.41.0

- Implemented floating features borrowing

### February 2, 2026, v7.40.0

- Added support for iOS hardware ID generation (use `DeviceIDAlgorithm.HardwareIdGeneratorDefault` - sdk auto detects iOS).
- Implemented license bundles (see the new BundleSample project in samples folder in the zip).
- Added Unity beta project to main zip (Unity sdk is no longer a separate download link).
- Fixed floating features registration information being reset on license check.
- Removed obsolete serializers in legacy and new .NET frameworks respectively, and replaced them with unified Newtonsoft.Json v13.0.4.

### January 14, 2026, v7.39.0

- Added SSO-based license borrowing for floating licenses (`ILicense.BorrowSSO` methods).
- Added `LicenseManager.GetAllSSOUrls` method for fetching all SSO urls from the LicenseSpring platform.
- Fixed license deactivation issue.

### December 21, 2025, v7.38.0

- Added an optional parameter to `License.DeactivateOffline` for sending device variables during license deactivation.

### November 8, 2025, v7.37.1

- Fixed an issue with validity duration in air-gap license activation.

### November 3, 2025, v7.37.0

- Added `ILicense.ActivationDate()` and `ILicense.ActivationDateUTC()` methods.
- Fixed an issue with serialization of base64 encoded data (i.e. in offline license activation).

### October 20, 2025, v7.36.2

- Improved offline licensing cryptography security.
- Reverted forcing TLS12.

### October 13, 2025, v7.36.1

- Fixed an issue with HWID generation on some target frameworks.
- Fixed an issue with nuget not being built for some target frameworks (.NET Standard and .NET 5+).
- Fixed misreferenced .NET 5+ and .NET standard `System.Text.Json` package references versions and updated to 9.0.0.

### October 12, 2025, v7.36.0

:::hint{type="danger"}
This version only built for .NET 4 and older frameworks due to a nuspec reference bug.
:::

Added support for Floating Server v2.

- Added `AirGapCryptographyMode` enum for selecting cryptography implementation when generating AirGap codes.
- Added `ExtendedOptions.AirGapCryptographyMode` property, defaults to `AirGapCryptographyMode.Auto`.

### September 17, 2025, v7.35.0

- Added Company reference to `License` and `Product`
- Added hardware key (YubiKey) support

:::hint{type="warning"}
Using Yubikey requires a third party Yubikey library which if not part of the downloadable zip on this page. If you are using Yubikey cryptography either download the sdk through the nuget package manager or manually handle required references. [**https://docs.yubico.com/yesdk/**](https://docs.yubico.com/yesdk/)
:::

### September 5, 2025, v7.33.6

- Fixed an issue with legacy airgap license policy files.

### September 4, 2025, v7.33.5

- Fixed an issue with AirGap code verification running on Windows 11.

:::hint{type="warning"}
Running the sdk on Windows 11 requires a third party library `BouncyCastle.Cryptography`, which is not part of the downloadable zip on this page. If you are using airgap licensing on Windows 11 - either download the sdk through the nuget package manager or manually handle required references. Dll is used only in `LicenseService.GetAirGapCode` and `LicenseService.VerifyConfirmationCode` [**https://www.nuget.org/packages/BouncyCastle.Cryptography**](https://www.nuget.org/packages/BouncyCastle.Cryptography)
:::

### August 28, 2025, v7.34.0-beta

- Integrated new hardware ID algorithms through the `hardware_id_generator.dll` and `libhardware_id_generator.so` libraries, depending on the OS.

:::hint{type="warning"}
This version adds a **runtime** reference to `hardware_id_generator.dll` and `libhardware_id_generator.so` libraries, which are used with new HWID algorithms. You can use these algorithms by setting the `DeviceIdAlgorithm` property of `ExtendedOptions` class, just like before:&#x20;

`new ExtendedOptions() { DeviceIdAlgorithm = DeviceIDAlgorithm.HardwareIdGeneratorDefault };`

All new algorithms are prefixed with `HardwareIdGenerator`.&#x20;

When downloading the SDK through the nuget package manager, if using legacy, .NET framework 4.x versions, the framework will copy the corresponding dll to your builld output folder (Debug or Release), depending on the current OS. If running new .NET frameworks, manager will create a folder called `runtimes` in your build output folder with all dll references. You can deploy only the packages you need, depending on the targeted OS of your application.

If downloading the SDK through the zip file on this page, the HWID dlls come bundled with the sdk so you can handle the build process manually.
:::

### July 31, 2025, v7.33.4

- Fixed an issue with AirGap licensing running on Windows 11.

:::hint{type="warning"}
Running the sdk on Windows 11 requires a third party library `BouncyCastle.Cryptography`, which is not part of the downloadable zip on this page. If you are using airgap licensing on Windows 11 either download the sdk through the nuget package manager or manually handle required references. Dll is used only in `LicenseService.GetAirGapCode` and `LicenseService.VerifyConfirmationCode` [**https://www.nuget.org/packages/BouncyCastle.Cryptography**](https://www.nuget.org/packages/BouncyCastle.Cryptography)
:::

### June 16, 2025 v7.33.3

- Fixed missing `user` parameter when releasing offline floating feature.
- Fixed generating air-gap code issue on .NET framework.

### June 12, 2025 v7.33.2

- Fixed missing `user` parameter when registering offline floating feature.

### May 29, 2025 v7.33.1

- Fixed an issue with HWID generation using windows alternative algorithm on some windows 11 LTSE versions.
- Added `System.Management` reference to .NET Standard 2.1 framework build.

### April 28, 2025 v7.33.0

- Added overloads with password parameter to floating license borrowing methods `ILicense.Borrow`.

### April 10, 2025 v7.32.1

- Fixed OAuth samples namespace issue.

### April 10, 2025 v7.32.0

- Added OAuth client credentials authentication support through a new `Configuration.cs` constructor.
- Added `ConfigurationFactory.CreateOAuthConfiguration` method.
- Updated `Config.cs` class in samples with the new constructor.

### March 5, 2025 v7.31.2

- Fixed Airgap licensing issue on linux

### February 23, 2025 v7.31.1

- Added env filter to `ProductDetails ILicenseManager.GetProductDetails(bool includeCustomFields, bool includeLatestVersion, string env)`
- Fixed nuget package signing issue (not related to SDK functionality).

### November 18, 2024 v7.30.0

-  Added parameter `AirgapSkipLocalTimeCheck` to `ExtendedOptions`. If set to true local licence check will ignore local time desynchronization. Works only with airgaped licences. Default is false.&#x20;

### October 17, 2024 v7.29.0

-  Implemented negative consumption on license and license features.
- Fixed `UserLicense.Customer` not being populated.
- Fixed null reference exception in floating client methods caused by `ServerId` property.
- Fixed web application not starting.

### July 26, 2024 v7.28.0

- Added overload method `ILicense ILicenseManager.ActivateLicense(LicenseID, DeviceVariable[])` which enables setting device variables on license activation.
- Added `UserLicensesData[] ILicenseManager.GetUserLicenses(string, string)` that retrieves all licenses for the provided username and password, and for the product this LicenseManager is initialized for.
- Added `long? ServerId` property to `ILicenseID`, used for activating user licenses if a single user has multiple licenses for the same product.
- Discontinued support for .NET frameworks 3.5 and 4.0.

### June 13, 2024, v7.27.1

- Added `Code` property to `LicenseActivationException` to differentiate between license\_transferred\_max\_times and license\_activated\_max\_times api error codes.
- Added `string OrderStoreId()` method to ILicense. Run check license to populate data.

### May 28, 2024, v7.26.1

- Fixed missing metadata values
- Cleaned up public documentation

### April 04, 2024, v7.26.0

- Added `BundleCode` property to `ExtendedOptions` for cases when a single user has a bundle and a single license for the same product
- Added `IncludeExpiredFeatures` property to `LicenseWatchdogSettings` to enable watchdog to work with expired feature
- Added .net8.0 suppor

### January 22, 2024, v7.25.0

- Implemented support for custom web headers by adding property `CustomHeaders` to `ExtendedOptions.cs`

### January 02, 2024, v7.24.1

- Fixed an issue with metadata being deserialized to null.

### December 19, 2023, v7.24.0

- Added optional parameter `includeExpiredFeatures` to `License.Check()` for retrieving expired license features.
- Added optional parameters `includeCustomFields` and `includeLatestVersion` to `ILicenseManager.GetProductDetails()` method.
- Added `AutoRelease` property to `ILicense` (if set to true calls `Release()` in `License` destructor).
- Fixed object reference exception when `WebRequest.DefaultWebProxy` is set to null.
- Fixed several documentation typos.

### November 16, 2023, v7.23.0

- Implemented [**floating features**](https://docs.licensespring.com/sdks/tutorials/licensing-scenarios/floating-features) functionality
- Implemented [**floating features**](https://docs.licensespring.com/sdks/tutorials/licensing-scenarios/floating-features) watchdog

### September 29, 2023, v7.22.1

- Fixed guid duplicate error for \``LicenseWatchdogSettings`\` class
- Fixed assembly registration issue



### September 21, 2023, v7.22.0

- Implemented grace period feature.
- Added `IsGracePeriodStarted`, `GracePeriodEndDateTime,` `GracePeriodEndDateTimeUTC `methods to `License` class.
- Added `GracePeriod` option to `ExtendedOptions` class.
- Renamed methods related to subscription grace period to `IsSubscriptionGracePeriodStarted`, `SubscriptionGracePeriod`.
- Fixed bug of incorrect `MaxActivations` value when unlimited license activation is enabled.
- Fixed false positive VMware detection.
- Improved detection of Hyper-V.
- Improved logging of VM detection.
- Added `RequestDateInvalidException`.
- Added method `TransferLimit` to `License` class, it shows limit of license transfers between devices.
- Added helper methods `IsDeviceTransferAllowed` and `IsDeviceTransferLimited`\`to `License` class.
- Updated console samples to print license device transfer limit.



### July 14, 2023, v7.21.0&#xD;

- Improved air-gap activation security
- Added `License.IsAirGapped`
- Added `License.PolicyId`
- Implemented air-gap license deactivation, added `License.DeactivateAirGap` and `License.GetAirGapDeactivationCode` methods
- Updated AirGapSample to handle air-gap deactivation

### June 26, 2023, v7.20.0&#xD;

- Improved Microsoft Hyper-V VM detection, fixed issues with false-positive detection.
- Improved exception handling for internal server errors.
- Moved verification of air gap confirmation code to `LicenseManager.ActivateAirGapLicense`, added `AirGapActivationException`.
- Added searching through policy files in case path to a directory is passed to `LicenseManager.ActivateAirGapLicense`.
- Fixed trial license detection issue for air-gap activation.
- Fixed signature check for offline floating licenses.
- Fixed last usage date time in trial mode.
- Fixed getting device id for Linux under WSL. You can download SDK zip from Google drive.

### June 09, 2023, v7.19.0&#xD;

- Security patch, that address vulnerability of bypassing license signature verification.
- Added detection of Azure VM.
- Updated WinFormSample.
- Updated documentation.

### June 02, 2023, v7.18.0&#xD;

- Added metadata field for `ProductDetails`, `Customer`, `License` and `LicenseFeature` classes.
- Fixed `ArgumentOutOfRangeException` on `License.ValidityWithGracePeriod` and `License.IsValid` for subscription licenses with grace period.

### May 24, 2023, v7.17.1&#xD;

- Fixed issue of freezing calling thread when stopping watchdog or releasing borrowed license.
- Updated documentation.

### May 22, 2023, v7.17.0&#xD;

- Updated LicenseWatchdog, added `LicenseWatchdogSettings` class. Added options: running the callback on every license check, handling `NetworkException` and `LicenseServerException`.
- Added handling borrowed license: if the license is borrowed, watchdog will be paused until borrowing end date time.
- Added `License.SetupLicenseWatchdog` method that takes `LicenseWatchdogSettings` as an argument. Updated WinForm sample to demonstrate usage of `LicenseWatchdogSettings`.
- Added `License.SetWatchdogTimeout` method.
- Fixed license borrowing using offline update files.

### May 09, 2023, v7.16.0&#xD;

- Added `License.CanBorrow` helper method.
- Added `License.Register` method, see SDK documentation.
- Implemented unlimited consumption for consumption license and consumption features.
- Added `License.IsUnlimitedConsumptionAllowed` method and `LicenseFeature.AllowUnlimitedConsumptions` property.
- Updated SDK demo samples. Improved handling of floating licenses.
- Updated documentation.
- Improved security check for offline license activation and refresh, implemented offline signature verification.
- Improved error handling for offline license activation and refresh, the SDK will throw more specific exceptions in case of errors.
- Added exception for not supported target builds for air-gap activation.

### April 06, 2023, v7.15.0&#xD;

- Added `ExtendedOptions.AlternateKey`, `ExtendedOptions.AlternateServiceURL` properties
- Improved security for `License.UpdateOffline` method.
- Fixed security issue when activating license offline on a different device.

### March 29, 2023, v7.14.0&#xD;

- Fixed issue of JSON serialization.
- Fixed several issues related to offline activation when license contains features and custom fields.

### March 22, 2023, v7.13.3&#xD;

- Improved VBA sample.
- Added SDK version to log file.
- Fixed issue getting WinAlternative device id for .Net Framework target builds.

### February 17, 2023, v7.13.2&#xD;

- Added `CustomerNotFoundException`
- Fixed license features synchronization issues.

### February 6, 2023, v7.13.1&#xD;

- Added `License.MaxBorrowTime`.
- Added `License.Borrow` overloaded method that accepts DateTime argument.
- Implemented `License.IsGracePeriodStarted`.
- Fixed issue of incorrect return value for `FloatingEndDateTime` method when license is borrowed.
- Updated ConsoleSample.

### February 1, 2023, v7.13.0&#xD;

- Added `InvalidApiKeyException`, `ReadOnlyApiKeyException`, `RevokedApiKeyException`, and `ApiKeyProductNotAllowedException`.
- Implemented grace period feature for Subscription licenses. See `License.GracePeriod` and `License.ValidityWithGracePeriod`.
- Added `FloatingTimeoutExpiredException`.
- Fixed several issues with local license check and license expiry check.
- Fixed issue with `CryptoProvider` creation for Configuration when changing credentials.
- Adjusted obfuscation level to prevent false positive detection the SDK as malware.

### January 11, 2023, v7.12.0&#xD;

- Added .NET 7 target build.
- Fixed issue of false positive malware detection in the SDK.
- Updated obfuscation.

### December 19, 2022, v7.11.0&#xD;

- Implemented new API set for managing device variables. See `DeviceVariable`, `License.GetDeviceVariables`, `License.AddDeviceVariable` etc. Now device variables a being stored along with local license, managing device variables available both locally and on the backend. See SDK documentation for more details.
- Implemented license borrowing feature. See `License.Borrow`.
- Implemented `DeviceIDAlgorithm.WinAlternative` algorithm, fixed device id issue for UWP and self-contained apps.
- Added `License.FloatingEndDateTime`, now floating license expires when floating period ends.
- Added `BorrowLicenseException`.
- Added `DateHeaderInvalidException`.
- Fixed `LicenseManager.RelinkLicense` method.
- Fixed param encoding issue for get queries.
- Improved obfuscation.

### October 27, 2022, v7.10.1&#xD;

- Fixed license signature verification error.
- Enlarged default network timeout, now default is 10 seconds.

### October 6, 2022, v7.10.0&#xD;

- Improved security, implemented license signature v2 verification.
- Implemented SSO activation using auth code instead of token.
- Added SSOSample project.
- Removed `License.Signature`.

### September 22, 2022, v7.9.1&#xD;

- Fixed issue of long delay on desktop platforms when getting device id and when `DeviceIdAlgorithm.AutoId` is set.
- Added `ExtendedOptions.CloudIdRequestTimeout` option. It allows control request timeout when querying cloud platforms for instance id.
- Improved obfuscation.

### September 8, 2022, v7.9.0&#xD;

- Added `Source: sdk` header.
- Added `License.StopLicenseWatchdog` method.
- Implemented sending optional param `sdk_lang`.
- Fixed several issues and improved SDK \<-> FloatingServer integration.
- Implemented getting instance id for GCP. Added `DeviceIDAlgorithm.CloudPlatformsId` and `DeviceIDAlgorithm.AutoId`. Removed `ExtendedOptions.WebServiceMode`.
- Fixed date conversion issue related to air gap activation.

### July 7, 2022, v7.8.0&#xD;

- Implemented methods `LicenseManager.GetSSOUrl` and `LicenseManager.ActivateLicense` for activation of user based licenses using Single Sign On.
- Implemented methods `LicenseManager.GetAirGapActivationCode`, `LicenseManager.VerifyConfirmationCode` and `LicenseManager.ActivateAirGapLicense` for activation of air gap licenses. Air gap licensing is available only in .NET Framework 4.7 or greater, .NET Standard, .NET 5.0 and .NET 6.0 libraries.
- Added AirGapSample project.
- Added `DeviceIDAlgorithm.Gen3` device ID calculation algorithm to generate shorter HardwareID. This option can be useful for air gap licenses.

### May 31, 2022, v7.7.0&#xD;

- Added .Net6 support and ConsoleSampleNet6.
- Added `DeviceIDAlgorithm` enumeration and `ExtendedOptions.DeviceIdAlgorithm` property.
- Implemented method for updating license to new device id algorithm, see documentation for `LicenseManager.RelinkLicense`.
- Setter for `LicenseID.Password` made public.
- Added `License.StartDate` method and `CannotBeActivatedNowException`, see SDK docs for more details.
- Added address info data to the `Customer` class (address, city, state, country, postcode).
- Implemented ability to set desired license policy when requesting trial license. See `LicenseManager.GetTrialLicense`.
- Added new properties for consumption features: `LicenseFeature.AllowOverages`, `LicenseFeature.MaxOverages`, `LicenseFeature.ResetConsumption` and `LicenseFeature.ConsumptionPeriod`.
- Updated SDK samples.

### November 11, 2021, v7.6.1&#xD;

- Fixed compatibility issue with licenses created by previous SDK versions.

### November 9, 2021, v7.6.0&#xD;

- Added `LicenseUser.IsInitialPassword` property.
- Added data check when sending device variables.
- Improved support of handling multiple licenses, added `BaseManager.ReloadLicense` method.
- Fixed ArgumentException error when removing SDK data in case data location is current directory.
- Fixed incorrect license path if it was set as an empty string through the ExtendedOptions.
- Fixed UUID duplicate error.
- Fixed minor issues in VM Detection module.
- Updated VBA sample.

### November 1, 2021, v7.5.0&#xD;

- Implemented VM detection, see `ExtendedOptions.EnableVMDetection` and `Configuration.IsVM`, `Configuration.DetectedVMName`.
- Added `VMIsNotAllowedException`.
- Added `License.LicenseUser` method. Added `LicenseUser.Id` property.
- Improved getting device id on Windows, improved error handling and logging.
- Fixed URL for offline activation page in WinForm sample.
- Fixed getting device ID in Xamarin sample.

### August 31, 2021, v7.4.1&#xD;

- Added new license data fields, see `License.TransferCount` and `License.FloatingSlotsInUse`.
- Updated samples and configuration.

### August 13, 2021, v7.4.0&#xD;

- Implemented new classes for interaction with on-premise floating server. See `FloatingClient`, `FloatingServerInfo`.
- Implemented feature of adding local consumption info (both for license and features) when deactivating license offline.
- Implemented IEquatable interface and operator == for `LicenseID`.
- Fixed issue losing local consumption data when updating license offline.

### July 19, 2021, v7.3.0&#xD;

- Added cloud platforms support: Implemented getting Azure VM instance ID, adapted the SDK for working in Azure. Implemented getting AWS VM instance ID.
- Added ASP.Net sample application.
- Added `ICryptoProvider` iterface and `CryptoProvider` class. Now it is possible to set crypto key and/or salt, or implement custom CryptoProvider.
- Implemented new license storage model. See `ILicenseStorage` interface and `LicenseMemoryStorage`, `LicenseFileStorage` classes. Now it possible to store local license in custom locations like your DB, Windows registry, etc, by implementing `ILicenseStorage` interface.
- Implemented interprocess synchronization for local license, see `LicenseFileStorageEx` class.
- Added new properties `LicenseManager.DataLocation`, `LicenseManager.LicenseFileName`. `LicenseManager.Initialize` now accepts `ILicenseStorage` as optional argument.
- Added new properties to `InstallationFile` class, see `EulaLink`, `ReleaseNotesLink`, `Channel`, `Size `and `Environment`.
- Implemented filtering of installation files by environment and channel, added new class `InstallationFileOptions`.
- Improved `License.UpdateOffline`, added support for files created by the LicenseSpring platform.
- Improved error handling, general refactoring and improvements.

### July 1, 2021, v7.2.0&#xD;

- Implemented getting information on license users, see `LicenseUser` and `LicenseManager.GetCustomerLicenseUsers`.
- `LicenseManager.GetTrialLicense` now returns `LicenseID`, that includes initial password for user-based licenses.
- Added new members to `InstallationFile` class, that allow implementation of intermediate updates. See `InstallationFile.ReleaseDate` and `InstallationFile.RequiredVersion`.
- Public keys was encrypted and moved to the code.
- Improved obfuscation.

### April 30, 2021, v7.1.0&#xD;

- Added new method `License.UpdateOffline`.
- Added diff file to make SDK update easier.
- Allowed overwriting OS version info in `Configuration`.
- Fixed unknown exception in case of expired license, now SDK throws suitable exception type `LicenseExpiredException`.
- Fixed issues running on mobile platforms.
- Improved error handling, added new exception types `LicenseDisabledException` and `LicenseInactiveException`.
- Improved samples, updated VBA sample.

### April 22, 2021, v7.0.0&#xD;

- Added new class `LicenseID`, generalized API calls for user-based and key-based products.
- Implemented `LicenseStatus` and added `LicenseDeletedException`, SDK throws it in case license was deleted by product admin.
- Allowed overwriting of network information (IP, MAC and hostname).
- Implemented caching of ProductDetails.
- Fixed connection issue when using SDK with Xamarin on iOS.
- Fixed unhandled exception issue when SDK runs in Unity for Android or iOS.
- Removed API and data types for creating licenses and orders, this API is transferred to separate Management SDK.
- General improvements and refactoring, simplified class names for `LicenseSpringConfiguration` and `LicenseSpringExtendedOptions`.

### March 15, 2021, v6.5.0&#xD;

- Implemented expiry date for `LicenseFeature`, see `LicenseFeature.ExpiryDate` and `LicenseFeature.IsExpired`.
- Allowed decreasing consumption, see new methods `License.UpdateConsumption` and `License.UpdateFeatureConsumption`.
- Added optional parameter `OverageRequest` to `License.SyncConsumption`.
- Fixed connection check when SDK runs in Mono runtime.
- Implemented support for Xamarin.Forms, added SDK sample for Xamarin.Forms Android and iOS.
- Improved samples.

### January 28, 2021, v6.4.0&#xD;

- Added .Net5.0 target build.
- Added new cross-platform sample.
- Removed reflection protection that was causing Unity editor and SmartAssembly to crash.
- Fixed port number in check connection method.

### November 18, 2020, v6.3.1&#xD;

- Added `LicenseSpringExtendedOptions.ProtectOfflineActivation` option.
- Fixed problem with offline activation.
- Fixed typo in config file for VB.Net sample.

### November 9, 2020, v6.3.0&#xD;

- Implemented SDK obfuscation.
- The assemblies have been signed with digital signature.
- Fixed check for connection when default proxy is being used.
- Fixed a few error messages.
- Minor fixes in WinForm sample.

### October 25, 2020, v6.2.0&#xD;

- Implemented change password feature for user-based products. See `LicenseManager.ChangePassword` and `License.ChangePassword`.
- Added new exception types `TrialLicenseExpiredException`, `PasswordChangeNotAllowedException` and `MissingParametersException`.
- Added helper method `License.MaintenanceDaysRemaining`.
- Fixed `License.DaysRemaining` counter.
- Fixed connection check in conjunction with proxy.
- Improved WinForm sample.

### October 8, 2020, v6.1.0&#xD;

- Security improvements for offline activation.
- Added new target Net Standard 2.1, it uses different API for device ID calculation compared to Net Standard 2.0 target. Please note device ID remains the same, just API changed.
- Added a few data members to `LicenseDetails`. See `LicenseDetails.MaintenanceEndDate`, `LicenseDetails.IsFloating` and others.
- Refactoring and performance improvements.
- Minor UI fixes in WinForm sample.

### July 27, 2020, v6.0.0&#xD;

- Added new classes `BaseManager` and `ManagementService`. Functionality divided into management and end-user license handling.
- Updated `LicenseDetails` and `OrderDetails` classes, added new data members.
- Implemented LicenseWatchdog (background thread) for auto license checks, see `License.SetupLicenseWatchdog`.
- Threadsafety and reliability improvements.
- Added new exception types `MaxFloatingReachedException` and `DeviceBlacklistedException`.
- Created package for NuGet, so LicenseSpring is now avalible on NuGet, see [**https://www.nuget.org/packages/LicenseSpring.NetSDK/**](https://www.nuget.org/packages/LicenseSpring.NetSDK/)
- Fixed hardware ID issue due to localization of some WMI fields. See `LicenseSpringExtendedOptions.UseNewHardwareID`.
- Minor fixes and improvements in Configuration.

### June 19, 2020, v5.5.0&#xD;

- Implemented increasing feature consumption in offline mode.
- Implemented Overages feature for Consumption license type. See `License.IsConsumptionOverageAllowed` and `License.MaxConsumptionOverage`.
- Implemented Floating licensing. See `License.IsFloating`, `License.FloatingTimeout`, `License.FloatingUsers` and `License.Release`
- Improved consumption handling. Added new methods `License.UpdateFeatureConsumption`, `LicenseFeature.LocalConsumption`.
- Added helper method `License.Feature`, it returns the feature code.
- Improved error handling and added new exception class `InvalidLicenseFeatureException`.
- Fixed `License.TimesActivated` count issue for offline activation.

### June 1, 2020, v5.4.5&#xD;

- Fixed assembly registration issue (Guid duplicate error).
- Fixed encoding issue (invalid BOM marker in requests) on macOS Mono runtime.
- Improved error handling.

### April 9, 2020, v5.4.4&#xD;

- .Net Standard build adapted for Linux and MacOS, now it's cross-platform, supported platforms are Windows, Linux and MacOS.
- Fixed and improved `ProxySettings` class and proxy related logic, for more details please see documentation.
- Updated documentation and other minor improvements.

### March 30, 2020, v5.4.3&#xD;

- Added `LicenseFeature.Name`, now it's possible to get License feature name not only code.
- Added XML documentation, so now SDK documentation can be accessed and viewed from the IDE.
- Fixed deactivation bug, `TimesActivated` value wasn't updated properly. Improved `License.Deactivate`, see documentation.
- Improved `License.IncreaseFeatureConsumption`, removed redundant check and increased performance.
- Added sample app for .Net Core target.
- For .Net standard build System.Management package updated to the latest stable version 4.7.0.

### March 19, 2020, v5.4.2&#xD;

- Fixed hardware ID issue for Unity Engine.
- Added helper method `License.IsMaintenancePeriodExpired`.
- Improved hardware ID algorithm. Does not throw exception if could not determine system disk ID.
- Improved error handling in case of network errors (like secure channel failure and others).

### February 28, 2020, v5.4.1&#xD;

- Added new helper method `LicenseManager.IsOnline`, for more details see documentation.
- `ProductDetails` information now also available for offline activated licenses, see `License.GetProductDetails`.
- Default license file path changed to %localappdata%\LicenseSpring%ProductCode%\License.key If you use default license path in your app license will be transferred to new location by the SDK automatically.
- Fixed issue of empty offline activation file and corrupted license file.
- Improved error handling, `LicenseFileException` accompanied by internal exception, added `NetworkException` wrapper, see documentation.

### February 20, 2020, v5.4.0&#xD;

- Added new `LicenseManager.GetTrialLicense` method. It accepts Customer object, when issuing trial license also new customer will be created or license will be assigned to existing customer.
- Added `License.LastCheckDateUTC` and fixed `License.DaysRemaining` method. See documentation for more details.
- Improved logging.
- Improved error handling, fixed exceptions messages.
- Added `APINotFoundException`, `ActivationFileException`, `UnknownLicenseSpringException` exceptions.
- Fixed issue of consumption features. Consumption changes were not stored to local license file properly.
- Fixed assembly registration warnings. Generic collections types was replaced with plain arrays for COM interop.
- Added interfaces for public classes, it's required for better COM interop.
- `License.SendCustomData` renamed to `License.SendDeviceData`.

### January 28, 2020, v5.3.1&#xD;

- Fixed issue with company data member in Customer object.
- `OrderDetails.OrderID` property now public.
- Fixed ClassInterfaceAttribute for some of the public classes and assigned Guids.

### January 22, 2020 v5.3.0&#xD;

- Added license owner information `License.Owner`, for more details see documentation.
- Added `License.IsValid` helper method, see documentation for more details.
- Fixed binary files (assembly dependencies and incorrect target framework versions).

### January 13, 2020 v5.2.0&#xD;

- Fixed HardwareID issue in case of foreign (not english) locale.
- Added "WebService" mode for situations in which there is no possibility to save license file locally. Can be enabled by `LicenseSpringExtendedOptions.WebServiceMode` property.

### December 20, 2019 v5.1.0&#xD;

- Added new API request `LicenseManager.GetProductDetails`, new class `ProductDetails`.
- Added `LicenseSpringConfiguration.LicenseSpringAPIVersion` property. It returns API version that SDK uses.
- API version field added to offline activation/deactivation files.
- `LicenseManager.GetTrialKey` replaced with `LicenseManager.GetTrialLicense`.
- Improved `LicenseManager.CreateOrder`, new class `LicenseDetails`.
- Improved console sample, now demonstrates both user-based and key-based licensing approaches.
- Added VB.Net sample.
- Added build for .Net 4.8 target.

### December 11, 2019 v5.0.0&#xD;

- Added documentation for the SDK. See documentation/Documentation.html.
- User-based licensing. See new API details in the documentation.
- Added new exception type `LicenseFileException`. Could be thrown in case license file was damaged.
- Constructor of the LicenseManager now public. See details in the documentation.
- Added new methods `License.MaxActivations` and `License.TimesActivated`.
  Added ability to track MAC address. `CollectHostNameAndLocalIP` property renamed to `CollectNetworkInfo`.
- Stability and performance improvements.

### October 23, 2019 v4.7.0&#xD;

- Added requests for creating licenses and orders. See `LicenseManager.CreateLicense` and `LicenseManager.CreateOrder`.
- Consumption license features. See `License.Features`, `License.IncreaseFeatureConsumption` and `LicenseFeature` class.
- Improved samples

### September 27, 2019 v4.6.0&#xD;

- New API request `License.SendCustomData`, it allows sending custom data to the platform. Data will be linked to a device, so on the platform see device variables.
- Changed license status logic, now it's possible to check whether license is active even if it was disabled. See `License.isActive`, `License.isEnabled` and `License.Status`.
- Added Windows Forms sample.
- Added .Net Standard 2.0 build.

### September 13, 2019 v4.5.1&#xD;

- Fixed online license check and updating license status
- Minor stability improvements

### September 9, 2019 v4.5.0&#xD;

- Added new feature - Custom product (license) data fields, see `License::CustomFields`.
- Fixed sending of optional parameters app name and version.
- Added `License::MaxDaysRemainingValue` constant.
- Fixed determining of OS name.

### August 19, 2019 v4.4.7&#xD;

- Added new API method `License::IsOfflineActivated`, returns true if license was activated in offline mode.
- Fixed a few minor bugs, `License::IsExpired` now returns correct value for inactive or disabled license.

### July 31, 2019 v4.4.6&#xD;

- Added ability to control network timeout interval.
- Added SDK builds for new .Net target framework versions (4.6.2, 4.7, 4.7.1 and 4.7.2).

### July 24, 2019, v4.4.4&#xD;

- Fixed expiry policy for subscription license type.
- Fixed license re-enabling issue.

### July 1, 2019, v4.4.3&#xD;

- Added ability to use alternate proxy and credentials, new class `ProxySettings`.

### June 20, 2019, v4.4.2&#xD;

- Fixed issue with default proxy credentials.
- `LicenseSpringConfiguration.HardwareID` now available for reading.

### June 13, 2019, v4.4.1&#xD;

- Detecting system clock cheating during local check, new exception type `DateTimeCheatingException`.
- New helper methods `DaysPassedSinceLastCheck`, `IsInitialized`.

### May 21, 2019, v4.4.0&#xD;

- Offline licensing. New methods - `GetOfflineActivationFile`, `ActivateLicenseOffline` and `DeactivateOffline`.
- Stability and performance improvements

### May 8, 2019 v4.3.1&#xD;

- Fixed serialization bug of maximum DateTime values.

### May 6, 2019 v4.3.0&#xD;

- Consumption licensing, new methods for ILicense - `IncreaseConsumptionCounter`, `TotalConsumptions`, `MaxConsumptions` and new exception type `NotEnoughConsumptionException`. See sample app for details.
- Online check of the license now returns `InstallationFile` of the last available product version.

### April 25, 2019&#xD;

- New license type - `Consumption`.
- Improved Hardware ID generation algorithm, now faster and less error prone.
- Added SDK usage sample from VBA scripts
- Fixed Factory classes that in use in COM interop (for VBA etc.)

### April 16, 2019&#xD;

- Ability to set custom hardware ID.
- `LicenseSpringExtendedOptions`, all optional SDK configuration properties now brought together in ExtendedOptions class, see sample app for details.
- `IsActive` was brought back for backward compatibility. Equivalent to `Status() == LicenseStatus.Active`.
- Stability and performance improvements, faster SDK initialization and license loading.
- Improved build script and sample app.


[title] Javadoc & Downloads
[path] SDKs/Java SDK/

## Latest Version

### Version 2.27.0

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.27.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.27.0/licensespring-core-2.27.0.jar)                                       | [**Core 2.27.0 Javadoc**](https://licensespring.dream-factory.hr/2.27.0/core/index.html)                         | [**Core 2.27.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.27.0/licensespring-core-osgi-2.27.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.27.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.27.0/licensespring-license-client-2.27.0.jar)         | [**License Client 2.27.0 Javadoc**](https://licensespring.dream-factory.hr/2.27.0/license-client/index.html)     | [**License Client 2.27.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.27.0/licensespring-license-client-osgi-2.27.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.27.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.27.0/licensespring-floating-client-2.27.0.jar)      | [**Floating Client 2.27.0 Javadoc**](https://licensespring.dream-factory.hr/2.27.0/floating-client/index.html)   | [**Floating Client 2.27.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.27.0/licensespring-floating-client-osgi-2.27.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.27.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.27.0/licensespring-license-management-2.27.0.jar) | [**Management SDK 2.27.0 Javadoc**](https://licensespring.dream-factory.hr/2.27.0/license-management/index.html) | [**Management SDK 2.27.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.27.0/licensespring-license-management-osgi-2.27.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

## OSGI Bundle Information

:::hint{type="info"}
LicenseSpring Core is a basic bundle that you need to add to your classpath no matter which other bundle you need. If you don't add Core bundle, other bundles won't work and will generate exceptions.
:::

### To use our SDK in your OSGi bundle/plug-in follow this instructions:

- Download LicenseSpring Core bundle from the link above
- Download other bundles based on your needs (see respective pages for each module to see which module you need)
- Open your OSGi project and paste the bundles you downloaded into root directory
- Go to META-INF/MANIFEST.MF and open your manifest file
- Add bundles into classpath (Runtime->Classpath->Add->.. pick bundles)
- Now you can use our SDK in your OSGi project

## Older Versions

### Version 2.26.1

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.26.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.26.1/licensespring-core-2.26.1.jar)                                       | [**Core 2.26.1 Javadoc**](https://licensespring.dream-factory.hr/2.26.1/core/index.html)                         | [**Core 2.26.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.26.1/licensespring-core-osgi-2.26.1.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.26.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.26.1/licensespring-license-client-2.26.1.jar)         | [**License Client 2.26.1 Javadoc**](https://licensespring.dream-factory.hr/2.26.1/license-client/index.html)     | [**License Client 2.26.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.26.1/licensespring-license-client-osgi-2.26.1.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.26.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.26.1/licensespring-floating-client-2.26.1.jar)      | [**Floating Client 2.26.1 Javadoc**](https://licensespring.dream-factory.hr/2.26.1/floating-client/index.html)   | [**Floating Client 2.26.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.26.1/licensespring-floating-client-osgi-2.26.1.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.26.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.26.1/licensespring-license-management-2.26.1.jar) | [**Management SDK 2.26.1 Javadoc**](https://licensespring.dream-factory.hr/2.26.1/license-management/index.html) | [**Management SDK 2.26.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.26.1/licensespring-license-management-osgi-2.26.1.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.26.0

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.26.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.26.0/licensespring-core-2.26.0.jar)                                       | [**Core 2.26.0 Javadoc**](https://licensespring.dream-factory.hr/2.26.0/core/index.html)                         | [**Core 2.26.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.26.0/licensespring-core-osgi-2.26.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.26.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.26.0/licensespring-license-client-2.26.0.jar)         | [**License Client 2.26.0 Javadoc**](https://licensespring.dream-factory.hr/2.26.0/license-client/index.html)     | [**License Client 2.26.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.26.0/licensespring-license-client-osgi-2.26.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.26.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.26.0/licensespring-floating-client-2.26.0.jar)      | [**Floating Client 2.26.0 Javadoc**](https://licensespring.dream-factory.hr/2.26.0/floating-client/index.html)   | [**Floating Client 2.26.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.26.0/licensespring-floating-client-osgi-2.26.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.26.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.26.0/licensespring-license-management-2.26.0.jar) | [**Management SDK 2.26.0 Javadoc**](https://licensespring.dream-factory.hr/2.26.0/license-management/index.html) | [**Management SDK 2.26.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.26.0/licensespring-license-management-osgi-2.26.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.25.1

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.25.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.25.1/licensespring-core-2.25.1.jar)                                       | [**Core 2.25.1 Javadoc**](https://licensespring.dream-factory.hr/2.25.1/core/index.html)                         | [**Core 2.25.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.25.1/licensespring-core-osgi-2.25.1.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.25.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.25.1/licensespring-license-client-2.25.1.jar)         | [**License Client 2.25.1 Javadoc**](https://licensespring.dream-factory.hr/2.25.1/license-client/index.html)     | [**License Client 2.25.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.25.1/licensespring-license-client-osgi-2.25.1.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.25.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.25.1/licensespring-floating-client-2.25.1.jar)      | [**Floating Client 2.25.1 Javadoc**](https://licensespring.dream-factory.hr/2.25.1/floating-client/index.html)   | [**Floating Client 2.25.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.25.1/licensespring-floating-client-osgi-2.25.1.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.25.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.25.1/licensespring-license-management-2.25.1.jar) | [**Management SDK 2.25.1 Javadoc**](https://licensespring.dream-factory.hr/2.25.1/license-management/index.html) | [**Management SDK 2.25.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.25.1/licensespring-license-management-osgi-2.25.1.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.25.0

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.25.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.25.0/licensespring-core-2.25.0.jar)                                       | [**Core 2.25.0 Javadoc**](https://licensespring.dream-factory.hr/2.25.0/core/index.html)                         | [**Core 2.25.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.25.0/licensespring-core-osgi-2.25.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.25.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.25.0/licensespring-license-client-2.25.0.jar)         | [**License Client 2.25.0 Javadoc**](https://licensespring.dream-factory.hr/2.25.0/license-client/index.html)     | [**License Client 2.25.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.25.0/licensespring-license-client-osgi-2.25.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.25.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.25.0/licensespring-floating-client-2.25.0.jar)      | [**Floating Client 2.25.0 Javadoc**](https://licensespring.dream-factory.hr/2.25.0/floating-client/index.html)   | [**Floating Client 2.25.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.25.0/licensespring-floating-client-osgi-2.25.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.25.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.25.0/licensespring-license-management-2.25.0.jar) | [**Management SDK 2.25.0 Javadoc**](https://licensespring.dream-factory.hr/2.25.0/license-management/index.html) | [**Management SDK 2.25.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.25.0/licensespring-license-management-osgi-2.25.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.24.1

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.24.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.24.0/licensespring-core-2.24.0.jar)                                       | [**Core 2.24.1 Javadoc**](https://licensespring.dream-factory.hr/2.24.0/core/index.html)                         | [**Core 2.24.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.24.0/licensespring-core-osgi-2.24.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.24.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.24.0/licensespring-license-client-2.24.0.jar)         | [**License Client 2.24.1 Javadoc**](https://licensespring.dream-factory.hr/2.24.0/license-client/index.html)     | [**License Client 2.24.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.24.0/licensespring-license-client-osgi-2.24.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.24.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.24.0/licensespring-floating-client-2.24.0.jar)      | [**Floating Client 2.24.1 Javadoc**](https://licensespring.dream-factory.hr/2.24.0/floating-client/index.html)   | [**Floating Client 2.24.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.24.0/licensespring-floating-client-osgi-2.24.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.24.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.24.0/licensespring-license-management-2.24.0.jar) | [**Management SDK 2.24.1 Javadoc**](https://licensespring.dream-factory.hr/2.24.0/license-management/index.html) | [**Management SDK 2.24.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.24.0/licensespring-license-management-osgi-2.24.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% method  |

### Version 2.24.0

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.24.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.24.0/licensespring-core-2.24.0.jar)                                       | [**Core 2.24.0 Javadoc**](https://licensespring.dream-factory.hr/2.24.0/core/index.html)                         | [**Core 2.24.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.24.0/licensespring-core-osgi-2.24.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.24.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.24.0/licensespring-license-client-2.24.0.jar)         | [**License Client 2.24.0 Javadoc**](https://licensespring.dream-factory.hr/2.24.0/license-client/index.html)     | [**License Client 2.24.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.24.0/licensespring-license-client-osgi-2.24.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.24.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.24.0/licensespring-floating-client-2.24.0.jar)      | [**Floating Client 2.24.0 Javadoc**](https://licensespring.dream-factory.hr/2.24.0/floating-client/index.html)   | [**Floating Client 2.24.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.24.0/licensespring-floating-client-osgi-2.24.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.24.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.24.0/licensespring-license-management-2.24.0.jar) | [**Management SDK 2.24.0 Javadoc**](https://licensespring.dream-factory.hr/2.24.0/license-management/index.html) | [**Management SDK 2.24.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.24.0/licensespring-license-management-osgi-2.24.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.23.1

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.23.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.23.1/licensespring-core-2.23.1.jar)                                       | [**Core 2.23.1 Javadoc**](https://licensespring.dream-factory.hr/2.23.1/core/index.html)                         | [**Core 2.23.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.23.1/licensespring-core-osgi-2.23.1.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.23.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.23.1/licensespring-license-client-2.23.1.jar)         | [**License Client 2.23.1 Javadoc**](https://licensespring.dream-factory.hr/2.23.1/license-client/index.html)     | [**License Client 2.23.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.23.1/licensespring-license-client-osgi-2.23.1.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.22. Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.23.1/licensespring-floating-client-2.23.1.jar)       | [**Floating Client 2.23.1 Javadoc**](https://licensespring.dream-factory.hr/2.23.1/floating-client/index.html)   | [**Floating Client 2.23.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.23.1/licensespring-floating-client-osgi-2.23.1.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.23.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.23.1/licensespring-license-management-2.23.1.jar) | [**Management SDK 2.23.1 Javadoc**](https://licensespring.dream-factory.hr/2.23.1/license-management/index.html) | [**Management SDK 2.23.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.23.1/licensespring-license-management-osgi-2.23.1.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.23.0

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.23.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.23.0/licensespring-core-2.23.0.jar)                                       | [**Core 2.23.0 Javadoc**](https://licensespring.dream-factory.hr/2.23.0/core/index.html)                         | [**Core 2.23.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.23.0/licensespring-core-osgi-2.23.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.23.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.23.0/licensespring-license-client-2.23.0.jar)         | [**License Client 2.23.0 Javadoc**](https://licensespring.dream-factory.hr/2.23.0/license-client/index.html)     | [**License Client 2.23.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.23.0/licensespring-license-client-osgi-2.23.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.22. Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.23.0/licensespring-floating-client-2.23.0.jar)       | [**Floating Client 2.23.0 Javadoc**](https://licensespring.dream-factory.hr/2.23.0/floating-client/index.html)   | [**Floating Client 2.23.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.23.0/licensespring-floating-client-osgi-2.23.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.23.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.23.0/licensespring-license-management-2.23.0.jar) | [**Management SDK 2.23.0 Javadoc**](https://licensespring.dream-factory.hr/2.23.0/license-management/index.html) | [**Management SDK 2.23.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.23.0/licensespring-license-management-osgi-2.23.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.22.0

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.22.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.22.0/licensespring-core-2.22.0.jar)                                       | [**Core 2.22.0 Javadoc**](https://licensespring.dream-factory.hr/2.22.0/core/index.html)                         | [**Core 2.22.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.22.0/licensespring-core-osgi-2.22.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.22.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.22.0/licensespring-license-client-2.22.0.jar)         | [**License Client 2.22.0 Javadoc**](https://licensespring.dream-factory.hr/2.22.0/license-client/index.html)     | [**License Client 2.22.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.22.0/licensespring-license-client-osgi-2.22.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.22. Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.22.0/licensespring-floating-client-2.22.0.jar)       | [**Floating Client 2.22.0 Javadoc**](https://licensespring.dream-factory.hr/2.22.0/floating-client/index.html)   | [**Floating Client 2.22.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.22.0/licensespring-floating-client-osgi-2.22.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.22.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.22.0/licensespring-license-management-2.22.0.jar) | [**Management SDK 2.22.0 Javadoc**](https://licensespring.dream-factory.hr/2.22.0/license-management/index.html) | [**Management SDK 2.22.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.22.0/licensespring-license-management-osgi-2.22.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.21.1

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.21.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.21.1/licensespring-core-2.21.1.jar)                                       | [**Core 2.21.1 Javadoc**](https://licensespring.dream-factory.hr/2.21.1/core/index.html)                         | [**Core 2.21.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.21.1/licensespring-core-osgi-2.21.1.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.21.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.21.1/licensespring-license-client-2.21.1.jar)         | [**License Client 2.21.1 Javadoc**](https://licensespring.dream-factory.hr/2.21.1/license-client/index.html)     | [**License Client 2.21.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.21.1/licensespring-license-client-osgi-2.21.1.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.21.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.21.1/licensespring-floating-client-2.21.1.jar)      | [**Floating Client 2.21.1 Javadoc**](https://licensespring.dream-factory.hr/2.21.1/floating-client/index.html)   | [**Floating Client 2.21.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.21.1/licensespring-floating-client-osgi-2.21.1.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.21.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.21.1/licensespring-license-management-2.21.1.jar) | [**Management SDK 2.21.1 Javadoc**](https://licensespring.dream-factory.hr/2.21.1/license-management/index.html) | [**Management SDK 2.21.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.21.1/licensespring-license-management-osgi-2.21.1.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.21.0

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.21.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.21.0/licensespring-core-2.21.0.jar)                                       | [**Core 2.21.0 Javadoc**](https://licensespring.dream-factory.hr/2.21.0/core/index.html)                         | [**Core 2.21.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.21.0/licensespring-core-osgi-2.21.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.21.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.21.0/licensespring-license-client-2.21.0.jar)         | [**License Client 2.21.0 Javadoc**](https://licensespring.dream-factory.hr/2.21.0/license-client/index.html)     | [**License Client 2.21.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.21.0/licensespring-license-client-osgi-2.21.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.21.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.21.0/licensespring-floating-client-2.21.0.jar)      | [**Floating Client 2.21.0 Javadoc**](https://licensespring.dream-factory.hr/2.21.0/floating-client/index.html)   | [**Floating Client 2.21.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.21.0/licensespring-floating-client-osgi-2.21.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.21.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.21.0/licensespring-license-management-2.21.0.jar) | [**Management SDK 2.21.0 Javadoc**](https://licensespring.dream-factory.hr/2.21.0/license-management/index.html) | [**Management SDK 2.21.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.21.0/licensespring-license-management-osgi-2.21.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.20.5

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.20.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.20.5/licensespring-core-2.20.5.jar)                                       | [**Core 2.20.5 Javadoc**](https://licensespring.dream-factory.hr/2.20.5/core/index.html)                         | [**Core 2.20.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.20.5/licensespring-core-osgi-2.20.5.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.20.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.20.5/licensespring-license-client-2.20.5.jar)         | [**License Client 2.20.5 Javadoc**](https://licensespring.dream-factory.hr/2.20.5/license-client/index.html)     | [**License Client 2.20.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.20.5/licensespring-license-client-osgi-2.20.5.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.20.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.20.5/licensespring-floating-client-2.20.5.jar)      | [**Floating Client 2.20.5 Javadoc**](https://licensespring.dream-factory.hr/2.20.5/floating-client/index.html)   | [**Floating Client 2.20.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.20.5/licensespring-floating-client-osgi-2.20.5.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.20.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.20.5/licensespring-license-management-2.20.5.jar) | [**Management SDK 2.20.5 Javadoc**](https://licensespring.dream-factory.hr/2.20.5/license-management/index.html) | [**Management SDK 2.20.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.20.5/licensespring-license-management-osgi-2.20.5.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.20.4

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.20.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.20.4/licensespring-core-2.20.4.jar)                                       | [**Core 2.20.4 Javadoc**](https://licensespring.dream-factory.hr/2.20.4/core/index.html)                         | [**Core 2.20.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.20.4/licensespring-core-osgi-2.20.4.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.20.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.20.4/licensespring-license-client-2.20.4.jar)         | [**License Client 2.20.4 Javadoc**](https://licensespring.dream-factory.hr/2.20.4/license-client/index.html)     | [**License Client 2.20.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.20.4/licensespring-license-client-osgi-2.20.4.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.20.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.20.4/licensespring-floating-client-2.20.4.jar)      | [**Floating Client 2.20.4 Javadoc**](https://licensespring.dream-factory.hr/2.20.4/floating-client/index.html)   | [**Floating Client 2.20.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.20.4/licensespring-floating-client-osgi-2.20.4.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.20.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.20.4/licensespring-license-management-2.20.4.jar) | [**Management SDK 2.20.4 Javadoc**](https://licensespring.dream-factory.hr/2.20.4/license-management/index.html) | [**Management SDK 2.20.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.20.4/licensespring-license-management-osgi-2.20.4.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.20.3

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.20.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.20.3/licensespring-core-2.20.3.jar)                                       | [**Core 2.20.3 Javadoc**](https://licensespring.dream-factory.hr/2.20.3/core/index.html)                         | [**Core 2.20.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.20.3/licensespring-core-osgi-2.20.3.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.20.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.20.3/licensespring-license-client-2.20.3.jar)         | [**License Client 2.20.3 Javadoc**](https://licensespring.dream-factory.hr/2.20.3/license-client/index.html)     | [**License Client 2.20.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.20.3/licensespring-license-client-osgi-2.20.3.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.20.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.20.3/licensespring-floating-client-2.20.3.jar)      | [**Floating Client 2.20.3 Javadoc**](https://licensespring.dream-factory.hr/2.20.3/floating-client/index.html)   | [**Floating Client 2.20.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.20.3/licensespring-floating-client-osgi-2.20.3.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.20.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.20.3/licensespring-license-management-2.20.3.jar) | [**Management SDK 2.20.3 Javadoc**](https://licensespring.dream-factory.hr/2.20.3/license-management/index.html) | [**Management SDK 2.20.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.20.3/licensespring-license-management-osgi-2.20.3.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.20.1

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.20.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.20.1/licensespring-core-2.20.1.jar)                                       | [**Core 2.20.1 Javadoc**](https://licensespring.dream-factory.hr/2.20.1/core/index.html)                         | [**Core 2.20.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.20.1/licensespring-core-osgi-2.20.1.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.20.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.20.1/licensespring-license-client-2.20.1.jar)         | [**License Client 2.20.1 Javadoc**](https://licensespring.dream-factory.hr/2.20.1/license-client/index.html)     | [**License Client 2.20.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.20.1/licensespring-license-client-osgi-2.20.1.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.20.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.20.1/licensespring-floating-client-2.20.1.jar)      | [**Floating Client 2.20.1 Javadoc**](https://licensespring.dream-factory.hr/2.20.1/floating-client/index.html)   | [**Floating Client 2.20.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.20.1/licensespring-floating-client-osgi-2.20.1.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.20.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.20.1/licensespring-license-management-2.20.1.jar) | [**Management SDK 2.20.1 Javadoc**](https://licensespring.dream-factory.hr/2.20.1/license-management/index.html) | [**Management SDK 2.20.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.20.1/licensespring-license-management-osgi-2.20.1.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.19.2

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.19.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.19.2/licensespring-core-2.19.2.jar)                                       | [**Core 2.19.2 Javadoc**](https://licensespring.dream-factory.hr/2.19.2/core/index.html)                         | [**Core 2.19.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.19.2/licensespring-core-osgi-2.19.2.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.19.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.19.2/licensespring-license-client-2.19.2.jar)         | [**License Client 2.19.2 Javadoc**](https://licensespring.dream-factory.hr/2.19.2/license-client/index.html)     | [**License Client 2.19.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.19.2/licensespring-license-client-osgi-2.19.2.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.19.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.19.2/licensespring-floating-client-2.19.2.jar)      | [**Floating Client 2.19.2 Javadoc**](https://licensespring.dream-factory.hr/2.19.2/floating-client/index.html)   | [**Floating Client 2.19.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.19.2/licensespring-floating-client-osgi-2.19.2.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.19.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.19.2/licensespring-license-management-2.19.2.jar) | [**Management SDK 2.19.2 Javadoc**](https://licensespring.dream-factory.hr/2.19.2/license-management/index.html) | [**Management SDK 2.19.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.19.2/licensespring-license-management-osgi-2.19.2.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.19.1

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.19.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.19.1/licensespring-core-2.19.1.jar)                                       | [**Core 2.19.1 Javadoc**](https://licensespring.dream-factory.hr/2.19.1/core/index.html)                         | [**Core 2.19.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.19.1/licensespring-core-osgi-2.19.1.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.19.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.19.1/licensespring-license-client-2.19.1.jar)         | [**License Client 2.19.1 Javadoc**](https://licensespring.dream-factory.hr/2.19.1/license-client/index.html)     | [**License Client 2.19.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.19.1/licensespring-license-client-osgi-2.19.1.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.19.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.19.1/licensespring-floating-client-2.19.1.jar)      | [**Floating Client 2.19.1 Javadoc**](https://licensespring.dream-factory.hr/2.19.1/floating-client/index.html)   | [**Floating Client 2.19.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.19.1/licensespring-floating-client-osgi-2.19.1.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.19.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.19.1/licensespring-license-management-2.19.1.jar) | [**Management SDK 2.19.1 Javadoc**](https://licensespring.dream-factory.hr/2.19.1/license-management/index.html) | [**Management SDK 2.19.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.19.1/licensespring-license-management-osgi-2.19.1.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.19.0

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.19.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.19.0/licensespring-core-2.19.0.jar)                                       | [**Core 2.19.0 Javadoc**](https://licensespring.dream-factory.hr/2.19.0/core/index.html)                         | [**Core 2.19.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.19.0/licensespring-core-osgi-2.19.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.19.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.19.0/licensespring-license-client-2.19.0.jar)         | [**License Client 2.19.0 Javadoc**](https://licensespring.dream-factory.hr/2.19.0/license-client/index.html)     | [**License Client 2.19.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.19.0/licensespring-license-client-osgi-2.19.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.19.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.19.0/licensespring-floating-client-2.19.0.jar)      | [**Floating Client 2.19.0 Javadoc**](https://licensespring.dream-factory.hr/2.19.0/floating-client/index.html)   | [**Floating Client 2.19.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.19.0/licensespring-floating-client-osgi-2.19.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.19.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.19.0/licensespring-license-management-2.19.0.jar) | [**Management SDK 2.19.0 Javadoc**](https://licensespring.dream-factory.hr/2.19.0/license-management/index.html) | [**Management SDK 2.19.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.19.0/licensespring-license-management-osgi-2.19.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.18.5

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.18.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.18.5/licensespring-core-2.18.5.jar)                                       | [**Core 2.18.5 Javadoc**](https://licensespring.dream-factory.hr/2.18.5/core/index.html)                         | [**Core 2.18.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.18.5/licensespring-core-osgi-2.18.5.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.18.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.18.5/licensespring-license-client-2.18.5.jar)         | [**License Client 2.18.5 Javadoc**](https://licensespring.dream-factory.hr/2.18.5/license-client/index.html)     | [**License Client 2.18.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.18.5/licensespring-license-client-osgi-2.18.5.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.18.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.18.5/licensespring-floating-client-2.18.5.jar)      | [**Floating Client 2.18.5 Javadoc**](https://licensespring.dream-factory.hr/2.18.5/floating-client/index.html)   | [**Floating Client 2.18.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.18.5/licensespring-floating-client-osgi-2.18.5.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.18.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.18.5/licensespring-license-management-2.18.5.jar) | [**Management SDK 2.18.5 Javadoc**](https://licensespring.dream-factory.hr/2.18.5/license-management/index.html) | [**Management SDK 2.18.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.18.5/licensespring-license-management-osgi-2.18.5.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.18.4

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.18.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.18.4/licensespring-core-2.18.4.jar)                                       | [**Core 2.18.4 Javadoc**](https://licensespring.dream-factory.hr/2.18.4/core/index.html)                         | [**Core 2.18.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.18.4/licensespring-core-osgi-2.18.4.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.18.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.18.4/licensespring-license-client-2.18.4.jar)         | [**License Client 2.18.4 Javadoc**](https://licensespring.dream-factory.hr/2.18.4/license-client/index.html)     | [**License Client 2.18.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.18.4/licensespring-license-client-osgi-2.18.4.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.18.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.18.4/licensespring-floating-client-2.18.4.jar)      | [**Floating Client 2.18.4 Javadoc**](https://licensespring.dream-factory.hr/2.18.4/floating-client/index.html)   | [**Floating Client 2.18.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.18.4/licensespring-floating-client-osgi-2.18.4.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.18.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.18.4/licensespring-license-management-2.18.4.jar) | [**Management SDK 2.18.4 Javadoc**](https://licensespring.dream-factory.hr/2.18.4/license-management/index.html) | [**Management SDK 2.18.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.18.4/licensespring-license-management-osgi-2.18.4.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.18.3

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.18.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.18.3/licensespring-core-2.18.3.jar)                                       | [**Core 2.18.3 Javadoc**](https://licensespring.dream-factory.hr/2.18.3/core/index.html)                         | [**Core 2.18.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.18.3/licensespring-core-osgi-2.18.3.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.18.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.18.3/licensespring-license-client-2.18.3.jar)         | [**License Client 2.18.3 Javadoc**](https://licensespring.dream-factory.hr/2.18.3/license-client/index.html)     | [**License Client 2.18.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.18.3/licensespring-license-client-osgi-2.18.3.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.18.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.18.3/licensespring-floating-client-2.18.3.jar)      | [**Floating Client 2.18.3 Javadoc**](https://licensespring.dream-factory.hr/2.18.3/floating-client/index.html)   | [**Floating Client 2.18.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.18.3/licensespring-floating-client-osgi-2.18.3.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.18.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.18.3/licensespring-license-management-2.18.3.jar) | [**Management SDK 2.18.3 Javadoc**](https://licensespring.dream-factory.hr/2.18.3/license-management/index.html) | [**Management SDK 2.18.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.18.3/licensespring-license-management-osgi-2.18.3.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.18.2

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.18.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.18.2/licensespring-core-2.18.2.jar)                                       | [**Core 2.18.2 Javadoc**](https://licensespring.dream-factory.hr/2.18.2/core/index.html)                         | [**Core 2.18.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.18.2/licensespring-core-osgi-2.18.2.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.18.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.18.2/licensespring-license-client-2.18.2.jar)         | [**License Client 2.18.2 Javadoc**](https://licensespring.dream-factory.hr/2.18.2/license-client/index.html)     | [**License Client 2.18.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.18.2/licensespring-license-client-osgi-2.18.2.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.18.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.18.2/licensespring-floating-client-2.18.2.jar)      | [**Floating Client 2.18.2 Javadoc**](https://licensespring.dream-factory.hr/2.18.2/floating-client/index.html)   | [**Floating Client 2.18.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.18.2/licensespring-floating-client-osgi-2.18.2.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.18.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.18.2/licensespring-license-management-2.18.2.jar) | [**Management SDK 2.18.2 Javadoc**](https://licensespring.dream-factory.hr/2.18.2/license-management/index.html) | [**Management SDK 2.18.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.18.2/licensespring-license-management-osgi-2.18.2.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.18.1

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.18.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.18.1/licensespring-core-2.18.1.jar)                                       | [**Core 2.18.1 Javadoc**](https://licensespring.dream-factory.hr/2.18.1/core/index.html)                         | [**Core 2.18.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.18.1/licensespring-core-osgi-2.18.1.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.18.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.18.1/licensespring-license-client-2.18.1.jar)         | [**License Client 2.18.1 Javadoc**](https://licensespring.dream-factory.hr/2.18.1/license-client/index.html)     | [**License Client 2.18.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.18.1/licensespring-license-client-osgi-2.18.1.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.18.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.18.1/licensespring-floating-client-2.18.1.jar)      | [**Floating Client 2.18.1 Javadoc**](https://licensespring.dream-factory.hr/2.18.1/floating-client/index.html)   | [**Floating Client 2.18.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.18.1/licensespring-floating-client-osgi-2.18.1.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.18.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.18.1/licensespring-license-management-2.18.1.jar) | [**Management SDK 2.18.1 Javadoc**](https://licensespring.dream-factory.hr/2.18.1/license-management/index.html) | [**Management SDK 2.18.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.18.1/licensespring-license-management-osgi-2.18.1.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.18.0

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.18.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.18.0/licensespring-core-2.18.0.jar)                                       | [**Core 2.18.0 Javadoc**](https://licensespring.dream-factory.hr/2.18.0/core/index.html)                         | [**Core 2.18.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.18.0/licensespring-core-osgi-2.18.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.18.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.18.0/licensespring-license-client-2.18.0.jar)         | [**License Client 2.18.0 Javadoc**](https://licensespring.dream-factory.hr/2.18.0/license-client/index.html)     | [**License Client 2.18.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.18.0/licensespring-license-client-osgi-2.18.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.18.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.18.0/licensespring-floating-client-2.18.0.jar)      | [**Floating Client 2.18.0 Javadoc**](https://licensespring.dream-factory.hr/2.18.0/floating-client/index.html)   | [**Floating Client 2.18.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.18.0/licensespring-floating-client-osgi-2.18.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.18.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.18.0/licensespring-license-management-2.18.0.jar) | [**Management SDK 2.18.0 Javadoc**](https://licensespring.dream-factory.hr/2.18.0/license-management/index.html) | [**Management SDK 2.18.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.18.0/licensespring-license-management-osgi-2.18.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.17.1

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.17.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.17.0/licensespring-core-2.17.0.jar)                                       | [**Core 2.17.1 Javadoc**](https://licensespring.dream-factory.hr/2.17.0/core/index.html)                         | [**Core 2.17.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.17.0/licensespring-core-osgi-2.17.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.17.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.17.0/licensespring-license-client-2.17.0.jar)         | [**License Client 2.17.1 Javadoc**](https://licensespring.dream-factory.hr/2.17.0/license-client/index.html)     | [**License Client 2.17.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.17.0/licensespring-license-client-osgi-2.17.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.17.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.17.0/licensespring-floating-client-2.17.0.jar)      | [**Floating Client 2.17.1 Javadoc**](https://licensespring.dream-factory.hr/2.17.0/floating-client/index.html)   | [**Floating Client 2.17.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.17.0/licensespring-floating-client-osgi-2.17.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.17.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.17.0/licensespring-license-management-2.17.0.jar) | [**Management SDK 2.17.1 Javadoc**](https://licensespring.dream-factory.hr/2.17.0/license-management/index.html) | [**Management SDK 2.17.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.17.0/licensespring-license-management-osgi-2.17.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.17.0

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.17.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.17.0/licensespring-core-2.17.0.jar)                                       | [**Core 2.17.0 Javadoc**](https://licensespring.dream-factory.hr/2.17.0/core/index.html)                         | [**Core 2.17.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.17.0/licensespring-core-osgi-2.17.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.17.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.17.0/licensespring-license-client-2.17.0.jar)         | [**License Client 2.17.0 Javadoc**](https://licensespring.dream-factory.hr/2.17.0/license-client/index.html)     | [**License Client 2.17.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.17.0/licensespring-license-client-osgi-2.17.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.17.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.17.0/licensespring-floating-client-2.17.0.jar)      | [**Floating Client 2.17.0 Javadoc**](https://licensespring.dream-factory.hr/2.17.0/floating-client/index.html)   | [**Floating Client 2.17.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.17.0/licensespring-floating-client-osgi-2.17.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.17.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.17.0/licensespring-license-management-2.17.0.jar) | [**Management SDK 2.17.0 Javadoc**](https://licensespring.dream-factory.hr/2.17.0/license-management/index.html) | [**Management SDK 2.17.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.17.0/licensespring-license-management-osgi-2.17.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.16.6

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.16.6 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.16.6/licensespring-core-2.16.6.jar)                                       | [**Core 2.16.6 Javadoc**](https://licensespring.dream-factory.hr/2.16.6/core/index.html)                         | [**Core 2.16.6 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.16.6/licensespring-core-osgi-2.16.6.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.16.6 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.16.6/licensespring-license-client-2.16.6.jar)         | [**License Client 2.16.6 Javadoc**](https://licensespring.dream-factory.hr/2.16.6/license-client/index.html)     | [**License Client 2.16.6 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.16.6/licensespring-license-client-osgi-2.16.6.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.16.6 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.16.6/licensespring-floating-client-2.16.6.jar)      | [**Floating Client 2.16.6 Javadoc**](https://licensespring.dream-factory.hr/2.16.6/floating-client/index.html)   | [**Floating Client 2.16.6 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.16.6/licensespring-floating-client-osgi-2.16.6.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.16.6 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.16.6/licensespring-license-management-2.16.6.jar) | [**Management SDK 2.16.6 Javadoc**](https://licensespring.dream-factory.hr/2.16.6/license-management/index.html) | [**Management SDK 2.16.6 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.16.6/licensespring-license-management-osgi-2.16.6.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.16.5

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.16.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.16.5/licensespring-core-2.16.5.jar)                                       | [**Core 2.16.5 Javadoc**](https://licensespring.dream-factory.hr/2.16.5/core/index.html)                         | [**Core 2.16.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.16.5/licensespring-core-osgi-2.16.5.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.16.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.16.5/licensespring-license-client-2.16.5.jar)         | [**License Client 2.16.5 Javadoc**](https://licensespring.dream-factory.hr/2.16.5/license-client/index.html)     | [**License Client 2.16.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.16.5/licensespring-license-client-osgi-2.16.5.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.16.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.16.5/licensespring-floating-client-2.16.5.jar)      | [**Floating Client 2.16.5 Javadoc**](https://licensespring.dream-factory.hr/2.16.5/floating-client/index.html)   | [**Floating Client 2.16.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.16.5/licensespring-floating-client-osgi-2.16.5.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.16.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.16.5/licensespring-license-management-2.16.5.jar) | [**Management SDK 2.16.5 Javadoc**](https://licensespring.dream-factory.hr/2.16.5/license-management/index.html) | [**Management SDK 2.16.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.16.5/licensespring-license-management-osgi-2.16.5.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.16.4

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.16.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.16.4/licensespring-core-2.16.4.jar)                                       | [**Core 2.16.4 Javadoc**](https://licensespring.dream-factory.hr/2.16.4/core/index.html)                         | [**Core 2.16.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.16.4/licensespring-core-osgi-2.16.4.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.16.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.16.4/licensespring-license-client-2.16.4.jar)         | [**License Client 2.16.4 Javadoc**](https://licensespring.dream-factory.hr/2.16.4/license-client/index.html)     | [**License Client 2.16.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.16.4/licensespring-license-client-osgi-2.16.4.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.16.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.16.4/licensespring-floating-client-2.16.4.jar)      | [**Floating Client 2.16.4 Javadoc**](https://licensespring.dream-factory.hr/2.16.4/floating-client/index.html)   | [**Floating Client 2.16.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.16.4/licensespring-floating-client-osgi-2.16.4.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.16.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.16.4/licensespring-license-management-2.16.4.jar) | [**Management SDK 2.16.4 Javadoc**](https://licensespring.dream-factory.hr/2.16.4/license-management/index.html) | [**Management SDK 2.16.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.16.4/licensespring-license-management-osgi-2.16.4.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.16.3

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.16.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.16.3/licensespring-core-2.16.3.jar)                                       | [**Core 2.16.3 Javadoc**](https://licensespring.dream-factory.hr/2.16.3/core/index.html)                         | [**Core 2.16.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.16.3/licensespring-core-osgi-2.16.3.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.16.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.16.3/licensespring-license-client-2.16.3.jar)         | [**License Client 2.16.3 Javadoc**](https://licensespring.dream-factory.hr/2.16.3/license-client/index.html)     | [**License Client 2.16.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.16.3/licensespring-license-client-osgi-2.16.3.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.16.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.16.3/licensespring-floating-client-2.16.3.jar)      | [**Floating Client 2.16.3 Javadoc**](https://licensespring.dream-factory.hr/2.16.3/floating-client/index.html)   | [**Floating Client 2.16.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.16.3/licensespring-floating-client-osgi-2.16.3.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.16.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.16.3/licensespring-license-management-2.16.3.jar) | [**Management SDK 2.16.3 Javadoc**](https://licensespring.dream-factory.hr/2.16.3/license-management/index.html) | [**Management SDK 2.16.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.16.3/licensespring-license-management-osgi-2.16.3.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.16.2

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.16.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.16.2/licensespring-core-2.16.2.jar)                                       | [**Core 2.16.2 Javadoc**](https://licensespring.dream-factory.hr/2.16.2/core/index.html)                         | [**Core 2.16.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.16.2/licensespring-core-osgi-2.16.2.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.16.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.16.2/licensespring-license-client-2.16.2.jar)         | [**License Client 2.16.2 Javadoc**](https://licensespring.dream-factory.hr/2.16.2/license-client/index.html)     | [**License Client 2.16.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.16.2/licensespring-license-client-osgi-2.16.2.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.16.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.16.2/licensespring-floating-client-2.16.2.jar)      | [**Floating Client 2.16.2 Javadoc**](https://licensespring.dream-factory.hr/2.16.2/floating-client/index.html)   | [**Floating Client 2.16.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.16.2/licensespring-floating-client-osgi-2.16.2.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.16.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.16.2/licensespring-license-management-2.16.2.jar) | [**Management SDK 2.16.2 Javadoc**](https://licensespring.dream-factory.hr/2.16.2/license-management/index.html) | [**Management SDK 2.16.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.16.2/licensespring-license-management-osgi-2.16.2.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.16.1

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.16.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.16.1/licensespring-core-2.16.1.jar)                                       | [**Core 2.16.1 Javadoc**](https://licensespring.dream-factory.hr/2.16.1/core/index.html)                         | [**Core 2.16.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.16.1/licensespring-core-osgi-2.16.1.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.16.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.16.1/licensespring-license-client-2.16.1.jar)         | [**License Client 2.16.1 Javadoc**](https://licensespring.dream-factory.hr/2.16.1/license-client/index.html)     | [**License Client 2.16.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.16.1/licensespring-license-client-osgi-2.16.1.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.16.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.16.1/licensespring-floating-client-2.16.1.jar)      | [**Floating Client 2.16.1 Javadoc**](https://licensespring.dream-factory.hr/2.16.1/floating-client/index.html)   | [**Floating Client 2.16.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.16.1/licensespring-floating-client-osgi-2.16.1.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.16.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.16.1/licensespring-license-management-2.16.1.jar) | [**Management SDK 2.16.1 Javadoc**](https://licensespring.dream-factory.hr/2.16.1/license-management/index.html) | [**Management SDK 2.16.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.16.1/licensespring-license-management-osgi-2.16.1.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.16.0

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.16.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.16.0/licensespring-core-2.16.0.jar)                                       | [**Core 2.16.0 Javadoc**](https://licensespring.dream-factory.hr/2.16.0/core/index.html)                         | [**Core 2.16.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.16.0/licensespring-core-osgi-2.16.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.16.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.16.0/licensespring-license-client-2.16.0.jar)         | [**License Client 2.16.0 Javadoc**](https://licensespring.dream-factory.hr/2.16.0/license-client/index.html)     | [**License Client 2.16.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.16.0/licensespring-license-client-osgi-2.16.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.16.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.16.0/licensespring-floating-client-2.16.0.jar)      | [**Floating Client 2.16.0 Javadoc**](https://licensespring.dream-factory.hr/2.16.0/floating-client/index.html)   | [**Floating Client 2.16.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.16.0/licensespring-floating-client-osgi-2.16.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.16.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.16.0/licensespring-license-management-2.16.0.jar) | [**Management SDK 2.16.0 Javadoc**](https://licensespring.dream-factory.hr/2.16.0/license-management/index.html) | [**Management SDK 2.16.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.16.0/licensespring-license-management-osgi-2.16.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.15.0

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.15.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.15.0/licensespring-core-2.15.0.jar)                                       | [**Core 2.15.0 Javadoc**](https://licensespring.dream-factory.hr/2.15.0/core/index.html)                         | [**Core 2.15.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.15.0/licensespring-core-osgi-2.15.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.15.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.15.0/licensespring-license-client-2.15.0.jar)         | [**License Client 2.15.0 Javadoc**](https://licensespring.dream-factory.hr/2.15.0/license-client/index.html)     | [**License Client 2.15.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.15.0/licensespring-license-client-osgi-2.15.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.15.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.15.0/licensespring-floating-client-2.15.0.jar)      | [**Floating Client 2.15.0 Javadoc**](https://licensespring.dream-factory.hr/2.15.0/floating-client/index.html)   | [**Floating Client 2.15.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.15.0/licensespring-floating-client-osgi-2.15.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.15.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.15.0/licensespring-license-management-2.15.0.jar) | [**Management SDK 2.15.0 Javadoc**](https://licensespring.dream-factory.hr/2.15.0/license-management/index.html) | [**Management SDK 2.15.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.15.0/licensespring-license-management-osgi-2.15.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.14.0

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.14.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.14.0/licensespring-core-2.14.0.jar)                                       | [**Core 2.14.0 Javadoc**](https://licensespring.dream-factory.hr/2.14.0/core/index.html)                         | [**Core 2.14.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.14.0/licensespring-core-osgi-2.14.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.14.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.14.0/licensespring-license-client-2.14.0.jar)         | [**License Client 2.14.0 Javadoc**](https://licensespring.dream-factory.hr/2.14.0/license-client/index.html)     | [**License Client 2.14.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.14.0/licensespring-license-client-osgi-2.14.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.14.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.14.0/licensespring-floating-client-2.14.0.jar)      | [**Floating Client 2.14.0 Javadoc**](https://licensespring.dream-factory.hr/2.14.0/floating-client/index.html)   | [**Floating Client 2.14.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.14.0/licensespring-floating-client-osgi-2.14.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.14.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.14.0/licensespring-license-management-2.14.0.jar) | [**Management SDK 2.14.0 Javadoc**](https://licensespring.dream-factory.hr/2.14.0/license-management/index.html) | [**Management SDK 2.14.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.14.0/licensespring-license-management-osgi-2.14.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.13.0

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.13.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.13.0/licensespring-core-2.13.0.jar)                                       | [**Core 2.13.0 Javadoc**](https://licensespring.dream-factory.hr/2.13.0/core/index.html)                         | [**Core 2.13.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.13.0/licensespring-core-osgi-2.13.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.13.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.13.0/licensespring-license-client-2.13.0.jar)         | [**License Client 2.13.0 Javadoc**](https://licensespring.dream-factory.hr/2.13.0/license-client/index.html)     | [**License Client 2.13.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.13.0/licensespring-license-client-osgi-2.13.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.13.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.13.0/licensespring-floating-client-2.13.0.jar)      | [**Floating Client 2.13.0 Javadoc**](https://licensespring.dream-factory.hr/2.13.0/floating-client/index.html)   | [**Floating Client 2.13.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.13.0/licensespring-floating-client-osgi-2.13.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.13.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.13.0/licensespring-license-management-2.13.0.jar) | [**Management SDK 2.13.0 Javadoc**](https://licensespring.dream-factory.hr/2.13.0/license-management/index.html) | [**Management SDK 2.13.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.13.0/licensespring-license-management-osgi-2.13.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.12.0

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.12.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.12.0/licensespring-core-2.12.0.jar)                                       | [**Core 2.12.0 Javadoc**](https://licensespring.dream-factory.hr/2.12.0/core/index.html)                         | [**Core 2.12.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.12.0/licensespring-core-osgi-2.12.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.12.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.12.0/licensespring-license-client-2.12.0.jar)         | [**License Client 2.12.0 Javadoc**](https://licensespring.dream-factory.hr/2.12.0/license-client/index.html)     | [**License Client 2.12.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.12.0/licensespring-license-client-osgi-2.12.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.12.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.12.0/licensespring-floating-client-2.12.0.jar)      | [**Floating Client 2.12.0 Javadoc**](https://licensespring.dream-factory.hr/2.12.0/floating-client/index.html)   | [**Floating Client 2.12.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.12.0/licensespring-floating-client-osgi-2.12.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.12.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.12.0/licensespring-license-management-2.12.0.jar) | [**Management SDK 2.12.0 Javadoc**](https://licensespring.dream-factory.hr/2.12.0/license-management/index.html) | [**Management SDK 2.12.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.12.0/licensespring-license-management-osgi-2.12.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.11.1

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.11.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.11.1/licensespring-core-2.11.1.jar)                                       | [**Core 2.11.1 Javadoc**](https://licensespring.dream-factory.hr/2.11.1/core/index.html)                         | [**Core 2.11.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.11.1/licensespring-core-osgi-2.11.1.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.11.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.11.1/licensespring-license-client-2.11.1.jar)         | [**License Client 2.11.1 Javadoc**](https://licensespring.dream-factory.hr/2.11.1/license-client/index.html)     | [**License Client 2.11.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.11.1/licensespring-license-client-osgi-2.11.1.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.11.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.11.1/licensespring-floating-client-2.11.1.jar)      | [**Floating Client 2.11.1 Javadoc**](https://licensespring.dream-factory.hr/2.11.1/floating-client/index.html)   | [**Floating Client 2.11.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.11.1/licensespring-floating-client-osgi-2.11.1.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.11.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.11.1/licensespring-license-management-2.11.1.jar) | [**Management SDK 2.11.1 Javadoc**](https://licensespring.dream-factory.hr/2.11.1/license-management/index.html) | [**Management SDK 2.11.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.11.1/licensespring-license-management-osgi-2.11.1.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.10.0

|                     | JAR                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.10.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.10.0/licensespring-core-2.10.0.jar)                                       | [**Core 2.10.0 Javadoc**](https://licensespring.dream-factory.hr/2.10.0/core/index.html)                         | [**Core 2.10.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.10.0/licensespring-core-osgi-2.10.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.10.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.10.0/licensespring-license-client-2.10.0.jar)         | [**License Client 2.10.0 Javadoc**](https://licensespring.dream-factory.hr/2.10.0/license-client/index.html)     | [**License Client 2.10.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.10.0/licensespring-license-client-osgi-2.10.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.10.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.10.0/licensespring-floating-client-2.10.0.jar)      | [**Floating Client 2.10.0 Javadoc**](https://licensespring.dream-factory.hr/2.10.0/floating-client/index.html)   | [**Floating Client 2.10.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.10.0/licensespring-floating-client-osgi-2.10.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.10.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.10.0/licensespring-license-management-2.10.0.jar) | [**Management SDK 2.10.0 Javadoc**](https://licensespring.dream-factory.hr/2.10.0/license-management/index.html) | [**Management SDK 2.10.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.10.0/licensespring-license-management-osgi-2.10.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.9.0

|                     | JAR                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.9.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.9.0/licensespring-core-2.9.0.jar)                                       | [**Core 2.9.0 Javadoc**](https://licensespring.dream-factory.hr/2.9.0/core/index.html)                         | [**Core 2.9.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.9.0/licensespring-core-osgi-2.9.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.9.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.9.0/licensespring-license-client-2.9.0.jar)         | [**License Client 2.9.0 Javadoc**](https://licensespring.dream-factory.hr/2.9.0/license-client/index.html)     | [**License Client 2.9.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.9.0/licensespring-license-client-osgi-2.9.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.9.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.9.0/licensespring-floating-client-2.9.0.jar)      | [**Floating Client 2.9.0 Javadoc**](https://licensespring.dream-factory.hr/2.9.0/floating-client/index.html)   | [**Floating Client 2.9.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.9.0/licensespring-floating-client-osgi-2.9.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.9.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.9.0/licensespring-license-management-2.9.0.jar) | [**Management SDK 2.9.0 Javadoc**](https://licensespring.dream-factory.hr/2.9.0/license-management/index.html) | [**Management SDK 2.9.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.9.0/licensespring-license-management-osgi-2.9.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.8.6

|                     | JAR                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.8.6 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.8.6/licensespring-core-2.8.6.jar)                                       | [**Core 2.8.6 Javadoc**](https://licensespring.dream-factory.hr/2.8.6/core/index.html)                         | [**Core 2.8.6 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.8.6/licensespring-core-osgi-2.8.6.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.8.6 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.8.6/licensespring-license-client-2.8.6.jar)         | [**License Client 2.8.6 Javadoc**](https://licensespring.dream-factory.hr/2.8.6/license-client/index.html)     | [**License Client 2.8.6 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.8.6/licensespring-license-client-osgi-2.8.6.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.8.6 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.8.6/licensespring-floating-client-2.8.6.jar)      | [**Floating Client 2.8.6 Javadoc**](https://licensespring.dream-factory.hr/2.8.6/floating-client/index.html)   | [**Floating Client 2.8.6 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.8.6/licensespring-floating-client-osgi-2.8.6.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.8.6 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.8.6/licensespring-license-management-2.8.6.jar) | [**Management SDK 2.8.6 Javadoc**](https://licensespring.dream-factory.hr/2.8.6/license-management/index.html) | [**Management SDK 2.8.6 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.8.6/licensespring-license-management-osgi-2.8.6.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.8.5

|                     | JAR                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.8.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.8.5/licensespring-core-2.8.5.jar)                                       | [**Core 2.8.5 Javadoc**](https://licensespring.dream-factory.hr/2.8.5/core/index.html)                         | [**Core 2.8.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.8.5/licensespring-core-osgi-2.8.5.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.8.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.8.5/licensespring-license-client-2.8.5.jar)         | [**License Client 2.8.5 Javadoc**](https://licensespring.dream-factory.hr/2.8.5/license-client/index.html)     | [**License Client 2.8.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.8.5/licensespring-license-client-osgi-2.8.5.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.8.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.8.5/licensespring-floating-client-2.8.5.jar)      | [**Floating Client 2.8.5 Javadoc**](https://licensespring.dream-factory.hr/2.8.5/floating-client/index.html)   | [**Floating Client 2.8.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.8.5/licensespring-floating-client-osgi-2.8.5.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.8.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.8.5/licensespring-license-management-2.8.5.jar) | [**Management SDK 2.8.5 Javadoc**](https://licensespring.dream-factory.hr/2.8.5/license-management/index.html) | [**Management SDK 2.8.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.8.5/licensespring-license-management-osgi-2.8.5.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.8.4

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.8.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.8.4/licensespring-core-2.8.4.jar)                                       | [**Core 2.8.4 Javadoc**](https://licensespring.dream-factory.hr/2.8.4/core/index.html)                         | [**Core 2.8.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.8.4/licensespring-core-osgi-2.8.4.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.8.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.8.4/licensespring-license-client-2.8.4.jar)         | [**License Client 2.8.4 Javadoc**](https://licensespring.dream-factory.hr/2.8.4/license-client/index.html)     | [**License Client 2.8.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.8.4/licensespring-license-client-osgi-2.8.4.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.8.4 Jar**](https://licensespring.dream-factory.hr/2.8.4/floating-client/index.html)                                                                                      | [**Floating Client 2.8.4 Javadoc**](https://licensespring.dream-factory.hr/2.8.4/floating-client/index.html)   | [**Floating Client 2.8.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.8.4/licensespring-floating-client-osgi-2.8.4.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.8.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.8.4/licensespring-license-management-2.8.4.jar) | [**Management SDK 2.8.4 Javadoc**](https://licensespring.dream-factory.hr/2.8.4/license-management/index.html) | [**Management SDK 2.8.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.8.4/licensespring-license-management-osgi-2.8.4.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.8.3

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.8.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.8.3/licensespring-core-2.8.3.jar)                                       | [**Core 2.8.3 Javadoc**](https://licensespring.dream-factory.hr/2.8.3/core/index.html)                         | [**Core 2.8.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.8.3/licensespring-core-osgi-2.8.3.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.8.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.8.3/licensespring-license-client-2.8.3.jar)         | [**License Client 2.8.3 Javadoc**](https://licensespring.dream-factory.hr/2.8.3/license-client/index.html)     | [**License Client 2.8.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.8.3/licensespring-license-client-osgi-2.8.3.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.8.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.8.3/licensespring-floating-client-2.8.3.jar)      | [**Floating Client 2.8.3 Javadoc**](https://licensespring.dream-factory.hr/2.8.3/floating-client/index.html)   | [**Floating Client 2.8.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.8.3/licensespring-floating-client-osgi-2.8.3.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.8.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.8.3/licensespring-license-management-2.8.3.jar) | [**Management SDK 2.8.3 Javadoc**](https://licensespring.dream-factory.hr/2.8.3/license-management/index.html) | [**Management SDK 2.8.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.8.3/licensespring-license-management-osgi-2.8.3.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.8.2

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.8.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.8.2/licensespring-core-2.8.2.jar)                                       | [**Core 2.8.2 Javadoc**](https://licensespring.dream-factory.hr/2.8.2/core/index.html)                         | [**Core 2.8.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.8.2/licensespring-core-osgi-2.8.2.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.8.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.8.2/licensespring-license-client-2.8.2.jar)         | [**License Client 2.8.2 Javadoc**](https://licensespring.dream-factory.hr/2.8.2/license-client/index.html)     | [**License Client 2.8.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.8.2/licensespring-license-client-osgi-2.8.2.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.8.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.8.2/licensespring-floating-client-2.8.2.jar)      | [**Floating Client 2.8.2 Javadoc**](https://licensespring.dream-factory.hr/2.8.2/floating-client/index.html)   | [**Floating Client 2.8.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.8.2/licensespring-floating-client-osgi-2.8.2.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.8.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.8.2/licensespring-license-management-2.8.2.jar) | [**Management SDK 2.8.2 Javadoc**](https://licensespring.dream-factory.hr/2.8.2/license-management/index.html) | [**Management SDK 2.8.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.8.2/licensespring-license-management-osgi-2.8.2.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.8.1

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.8.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.8.1/licensespring-core-2.8.1.jar)                                       | [**Core 2.8.1 Javadoc**](https://licensespring.dream-factory.hr/2.8.1/core/index.html)                         | [**Core 2.8.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.8.1/licensespring-core-osgi-2.8.1.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.8.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.8.1/licensespring-license-client-2.8.1.jar)         | [**License Client 2.8.1 Javadoc**](https://licensespring.dream-factory.hr/2.8.1/license-client/index.html)     | [**License Client 2.8.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.8.1/licensespring-license-client-osgi-2.8.1.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.8.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.8.1/licensespring-floating-client-2.8.1.jar)      | [**Floating Client 2.8.1 Javadoc**](https://licensespring.dream-factory.hr/2.8.1/floating-client/index.html)   | [**Floating Client 2.8.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.8.1/licensespring-floating-client-osgi-2.8.1.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.8.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.8.1/licensespring-license-management-2.8.1.jar) | [**Management SDK 2.8.1 Javadoc**](https://licensespring.dream-factory.hr/2.8.1/license-management/index.html) | [**Management SDK 2.8.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.8.1/licensespring-license-management-osgi-2.8.1.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.8.0

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.8.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.8.0/licensespring-core-2.8.0.jar)                                       | [**Core 2.8.0 Javadoc**](https://licensespring.dream-factory.hr/2.8.0/core/index.html)                         | [**Core 2.8.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.8.0/licensespring-core-osgi-2.8.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.8.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.8.0/licensespring-license-client-2.8.0.jar)         | [**License Client 2.8.0 Javadoc**](https://licensespring.dream-factory.hr/2.8.0/license-client/index.html)     | [**License Client 2.8.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.8.0/licensespring-license-client-osgi-2.8.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.8.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.8.0/licensespring-floating-client-2.8.0.jar)      | [**Floating Client 2.8.0 Javadoc**](https://licensespring.dream-factory.hr/2.8.0/floating-client/index.html)   | [**Floating Client 2.8.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.8.0/licensespring-floating-client-osgi-2.8.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.8.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.8.0/licensespring-license-management-2.8.0.jar) | [**Management SDK 2.8.0 Javadoc**](https://licensespring.dream-factory.hr/2.8.0/license-management/index.html) | [**Management SDK 2.8.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.8.0/licensespring-license-management-osgi-2.8.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.7.0

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.7.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.7.0/licensespring-core-2.7.0.jar)                                       | [**Core 2.7.0 Javadoc**](https://licensespring.dream-factory.hr/2.7.0/core/index.html)                         | [**Core 2.7.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.7.0/licensespring-core-osgi-2.7.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.7.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.7.0/licensespring-license-client-2.7.0.jar)         | [**License Client 2.7.0 Javadoc**](https://licensespring.dream-factory.hr/2.7.0/license-client/index.html)     | [**License Client 2.7.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.7.0/licensespring-license-client-osgi-2.7.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.7.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.7.0/licensespring-floating-client-2.7.0.jar)      | [**Floating Client 2.7.0 Javadoc**](https://licensespring.dream-factory.hr/2.7.0/floating-client/index.html)   | [**Floating Client 2.7.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.7.0/licensespring-floating-client-osgi-2.7.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.7.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.7.0/licensespring-license-management-2.7.0.jar) | [**Management SDK 2.7.0 Javadoc**](https://licensespring.dream-factory.hr/2.7.0/license-management/index.html) | [**Management SDK 2.7.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.7.0/licensespring-license-management-osgi-2.7.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.6.2

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.6.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.6.2/licensespring-core-2.6.2.jar)                                       | [**Core 2.6.2 Javadoc**](https://licensespring.dream-factory.hr/2.6.2/core/index.html)                         | [**Core 2.6.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.6.2/licensespring-core-osgi-2.6.2.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.6.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.6.2/licensespring-license-client-2.6.2.jar)         | [**License Client 2.6.2 Javadoc**](https://licensespring.dream-factory.hr/2.6.2/license-client/index.html)     | [**License Client 2.6.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.6.2/licensespring-license-client-osgi-2.6.2.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.6.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.6.2/licensespring-floating-client-2.6.2.jar)      | [**Floating Client 2.6.2 Javadoc**](https://licensespring.dream-factory.hr/2.6.2/floating-client/index.html)   | [**Floating Client 2.6.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.6.2/licensespring-floating-client-osgi-2.6.2.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.6.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.6.2/licensespring-license-management-2.6.2.jar) | [**Management SDK 2.6.2 Javadoc**](https://licensespring.dream-factory.hr/2.6.2/license-management/index.html) | [**Management SDK 2.6.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.6.2/licensespring-license-management-osgi-2.6.2.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.6.1

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.6.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.6.1/licensespring-core-2.6.1.jar)                                       | [**Core 2.6.1 Javadoc**](https://licensespring.dream-factory.hr/2.6.1/core/index.html)                         | [**Core 2.6.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.6.1/licensespring-core-osgi-2.6.1.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.6.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.6.1/licensespring-license-client-2.6.1.jar)         | [**License Client 2.6.1 Javadoc**](https://licensespring.dream-factory.hr/2.6.1/license-client/index.html)     | [**License Client 2.6.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.6.1/licensespring-license-client-osgi-2.6.1.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.6.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.6.1/licensespring-floating-client-2.6.1.jar)      | [**Floating Client 2.6.1 Javadoc**](https://licensespring.dream-factory.hr/2.6.1/floating-client/index.html)   | [**Floating Client 2.6.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.6.1/licensespring-floating-client-osgi-2.6.1.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.6.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.6.1/licensespring-license-management-2.6.1.jar) | [**Management SDK 2.6.1 Javadoc**](https://licensespring.dream-factory.hr/2.6.1/license-management/index.html) | [**Management SDK 2.6.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.6.1/licensespring-license-management-osgi-2.6.1.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.6.0

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.6.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.6.0/licensespring-core-2.6.0.jar)                                       | [**Core 2.6.0 Javadoc**](https://licensespring.dream-factory.hr/2.6.0/core/index.html)                         | [**Core 2.6.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.6.0/licensespring-core-osgi-2.6.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.6.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.6.0/licensespring-license-client-2.6.0.jar)         | [**License Client 2.6.0 Javadoc**](https://licensespring.dream-factory.hr/2.6.0/license-client/index.html)     | [**License Client 2.6.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.6.0/licensespring-license-client-osgi-2.6.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.6.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.6.0/licensespring-floating-client-2.6.0.jar)      | [**Floating Client 2.6.0 Javadoc**](https://licensespring.dream-factory.hr/2.6.0/floating-client/index.html)   | [**Floating Client 2.6.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.6.0/licensespring-floating-client-osgi-2.6.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.6.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.6.0/licensespring-license-management-2.6.0.jar) | [**Management SDK 2.6.0 Javadoc**](https://licensespring.dream-factory.hr/2.6.0/license-management/index.html) | [**Management SDK 2.6.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.6.0/licensespring-license-management-osgi-2.6.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.5.9

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.5.9 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.5.9/licensespring-core-2.5.9.jar)                                       | [**Core 2.5.9 Javadoc**](https://licensespring.dream-factory.hr/2.5.9/core/index.html)                         | [**Core 2.5.9 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.5.9/licensespring-core-osgi-2.5.9.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.5.9 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.5.9/licensespring-license-client-2.5.9.jar)         | [**License Client 2.5.9 Javadoc**](https://licensespring.dream-factory.hr/2.5.9/license-client/index.html)     | [**License Client 2.5.9 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.5.9/licensespring-license-client-osgi-2.5.9.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.5.9 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.5.9/licensespring-floating-client-2.5.9.jar)      | [**Floating Client 2.5.9 Javadoc**](https://licensespring.dream-factory.hr/2.5.9/floating-client/index.html)   | [**Floating Client 2.5.9 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.5.9/licensespring-floating-client-osgi-2.5.9.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.5.9 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.5.9/licensespring-license-management-2.5.9.jar) | [**Management SDK 2.5.9 Javadoc**](https://licensespring.dream-factory.hr/2.5.9/license-management/index.html) | [**Management SDK 2.5.9 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.5.9/licensespring-license-management-osgi-2.5.9.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.5.8

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.5.8 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.5.8/licensespring-core-2.5.8.jar)                                       | [**Core 2.5.8 Javadoc**](https://licensespring.dream-factory.hr/2.5.8/core/index.html)                         | [**Core 2.5.8 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.5.8/licensespring-core-osgi-2.5.8.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.5.8 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.5.8/licensespring-license-client-2.5.8.jar)         | [**License Client 2.5.8 Javadoc**](https://licensespring.dream-factory.hr/2.5.8/license-client/index.html)     | [**License Client 2.5.8 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.5.8/licensespring-license-client-osgi-2.5.8.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.5.8 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.5.8/licensespring-floating-client-2.5.8.jar)      | [**Floating Client 2.5.8 Javadoc**](https://licensespring.dream-factory.hr/2.5.8/floating-client/index.html)   | [**Floating Client 2.5.8 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.5.8/licensespring-floating-client-osgi-2.5.8.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.5.8 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.5.8/licensespring-license-management-2.5.8.jar) | [**Management SDK 2.5.8 Javadoc**](https://licensespring.dream-factory.hr/2.5.8/license-management/index.html) | [**Management SDK 2.5.8 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.5.8/licensespring-license-management-osgi-2.5.8.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.5.7

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.5.7 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.5.7/licensespring-core-2.5.7.jar)                                       | [**Core 2.5.7 Javadoc**](https://licensespring.dream-factory.hr/2.5.7/core/index.html)                         | [**Core 2.5.7 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.5.7/licensespring-core-osgi-2.5.7.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.5.7 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.5.7/licensespring-license-client-2.5.7.jar)         | [**License Client 2.5.7 Javadoc**](https://licensespring.dream-factory.hr/2.5.7/license-client/index.html)     | [**License Client 2.5.7 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.5.7/licensespring-license-client-osgi-2.5.7.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.5.7 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.5.7/licensespring-floating-client-2.5.7.jar)      | [**Floating Client 2.5.7 Javadoc**](https://licensespring.dream-factory.hr/2.5.7/floating-client/index.html)   | [**Floating Client 2.5.7 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.5.7/licensespring-floating-client-osgi-2.5.7.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.5.7 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.5.7/licensespring-license-management-2.5.7.jar) | [**Management SDK 2.5.7 Javadoc**](https://licensespring.dream-factory.hr/2.5.7/license-management/index.html) | [**Management SDK 2.5.7 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.5.7/licensespring-license-management-osgi-2.5.7.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.5.6

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.5.6 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.5.6/licensespring-core-2.5.6.jar)                                       | [**Core 2.5.6 Javadoc**](https://licensespring.dream-factory.hr/2.5.6/core/index.html)                         | [**Core 2.5.6 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.5.6/licensespring-core-osgi-2.5.6.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.5.6 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.5.6/licensespring-license-client-2.5.6.jar)         | [**License Client 2.5.6 Javadoc**](https://licensespring.dream-factory.hr/2.5.6/license-client/index.html)     | [**License Client 2.5.6 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.5.6/licensespring-license-client-osgi-2.5.6.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.5.6 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.5.6/licensespring-floating-client-2.5.6.jar)      | [**Floating Client 2.5.6 Javadoc**](https://licensespring.dream-factory.hr/2.5.6/floating-client/index.html)   | [**Floating Client 2.5.6 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.5.6/licensespring-floating-client-osgi-2.5.6.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.5.6 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.5.6/licensespring-license-management-2.5.6.jar) | [**Management SDK 2.5.6 Javadoc**](https://licensespring.dream-factory.hr/2.5.6/license-management/index.html) | [**Management SDK 2.5.6 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.5.6/licensespring-license-management-osgi-2.5.6.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.5.5

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.5.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.5.5/licensespring-core-2.5.5.jar)                                       | [**Core 2.5.5 Javadoc**](https://licensespring.dream-factory.hr/2.5.5/core/index.html)                         | [**Core 2.5.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.5.5/licensespring-core-osgi-2.5.5.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.5.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.5.5/licensespring-license-client-2.5.5.jar)         | [**License Client 2.5.5 Javadoc**](https://licensespring.dream-factory.hr/2.5.5/license-client/index.html)     | [**License Client 2.5.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.5.5/licensespring-license-client-osgi-2.5.5.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.5.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.5.5/licensespring-floating-client-2.5.5.jar)      | [**Floating Client 2.5.5 Javadoc**](https://licensespring.dream-factory.hr/2.5.5/floating-client/index.html)   | [**Floating Client 2.5.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.5.5/licensespring-floating-client-osgi-2.5.5.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.5.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.5.5/licensespring-license-management-2.5.5.jar) | [**Management SDK 2.5.5 Javadoc**](https://licensespring.dream-factory.hr/2.5.5/license-management/index.html) | [**Management SDK 2.5.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.5.5/licensespring-license-management-osgi-2.5.5.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.5.4

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.5.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.5.4/licensespring-core-2.5.4.jar)                                       | [**Core 2.5.4 Javadoc**](https://licensespring.dream-factory.hr/2.5.4/core/index.html)                         | [**Core 2.5.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.5.4/licensespring-core-osgi-2.5.4.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.5.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.5.4/licensespring-license-client-2.5.4.jar)         | [**License Client 2.5.4 Javadoc**](https://licensespring.dream-factory.hr/2.5.4/license-client/index.html)     | [**License Client 2.5.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.5.4/licensespring-license-client-osgi-2.5.4.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.5.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.5.4/licensespring-floating-client-2.5.4.jar)      | [**Floating Client 2.5.4 Javadoc**](https://licensespring.dream-factory.hr/2.5.4/floating-client/index.html)   | [**Floating Client 2.5.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.5.4/licensespring-floating-client-osgi-2.5.4.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.5.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.5.4/licensespring-license-management-2.5.4.jar) | [**Management SDK 2.5.4 Javadoc**](https://licensespring.dream-factory.hr/2.5.4/license-management/index.html) | [**Management SDK 2.5.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.5.4/licensespring-license-management-osgi-2.5.4.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.5.3

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.5.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.5.3/licensespring-core-2.5.3.jar)                                       | [**Core 2.5.3 Javadoc**](https://licensespring.dream-factory.hr/2.5.3/core/index.html)                         | [**Core 2.5.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.5.3/licensespring-core-osgi-2.5.3.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.5.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.5.3/licensespring-license-client-2.5.3.jar)         | [**License Client 2.5.3 Javadoc**](https://licensespring.dream-factory.hr/2.5.3/license-client/index.html)     | [**License Client 2.5.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.5.3/licensespring-license-client-osgi-2.5.3.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.5.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.5.3/licensespring-floating-client-2.5.3.jar)      | [**Floating Client 2.5.3 Javadoc**](https://licensespring.dream-factory.hr/2.5.3/floating-client/index.html)   | [**Floating Client 2.5.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.5.3/licensespring-floating-client-osgi-2.5.3.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.5.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.5.3/licensespring-license-management-2.5.3.jar) | [**Management SDK 2.5.3 Javadoc**](https://licensespring.dream-factory.hr/2.5.3/license-management/index.html) | [**Management SDK 2.5.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.5.3/licensespring-license-management-osgi-2.5.3.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.5.2

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.5.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.5.2/licensespring-core-2.5.2.jar)                                       | [**Core 2.5.2 Javadoc**](https://licensespring.dream-factory.hr/2.5.2/core/index.html)                         | [**Core 2.5.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.5.2/licensespring-core-osgi-2.5.2.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.5.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.5.2/licensespring-license-client-2.5.2.jar)         | [**License Client 2.5.2 Javadoc**](https://licensespring.dream-factory.hr/2.5.2/license-client/index.html)     | [**License Client 2.5.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.5.2/licensespring-license-client-osgi-2.5.2.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.5.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.5.2/licensespring-floating-client-2.5.2.jar)      | [**Floating Client 2.5.2 Javadoc**](https://licensespring.dream-factory.hr/2.5.2/floating-client/index.html)   | [**Floating Client 2.5.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.5.2/licensespring-floating-client-osgi-2.5.2.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.5.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.5.2/licensespring-license-management-2.5.2.jar) | [**Management SDK 2.5.2 Javadoc**](https://licensespring.dream-factory.hr/2.5.2/license-management/index.html) | [**Management SDK 2.5.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.5.2/licensespring-license-management-osgi-2.5.2.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.5.1

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.5.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.5.1/licensespring-core-2.5.1.jar)                                       | [**Core 2.5.1 Javadoc**](https://licensespring.dream-factory.hr/2.5.1/core/index.html)                         | [**Core 2.5.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.5.1/licensespring-core-osgi-2.5.1.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.5.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.5.1/licensespring-license-client-2.5.1.jar)         | [**License Client 2.5.1 Javadoc**](https://licensespring.dream-factory.hr/2.5.1/license-client/index.html)     | [**License Client 2.5.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.5.1/licensespring-license-client-osgi-2.5.1.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.5.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.5.1/licensespring-floating-client-2.5.1.jar)      | [**Floating Client 2.5.1 Javadoc**](https://licensespring.dream-factory.hr/2.5.1/floating-client/index.html)   | [**License Client 2.5.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.5.1/licensespring-license-client-osgi-2.5.1.jar)         | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.5.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.5.1/licensespring-license-management-2.5.1.jar) | [**Management SDK 2.5.1 Javadoc**](https://licensespring.dream-factory.hr/2.5.1/license-management/index.html) | [**Management SDK 2.5.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.5.1/licensespring-license-management-osgi-2.5.1.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.5.0

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.5.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.5.0/licensespring-core-2.5.0.jar)                                       | [**Core 2.5.0 Javadoc**](https://licensespring.dream-factory.hr/2.5.0/core/index.html)                         | [**Core 2.5.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.5.0/licensespring-core-osgi-2.5.0.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.5.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.5.0/licensespring-license-client-2.5.0.jar)         | [**License Client 2.5.0 Javadoc**](https://licensespring.dream-factory.hr/2.5.0/license-client/index.html)     | [**License Client 2.5.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.5.0/licensespring-license-client-osgi-2.5.0.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.5.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.5.0/licensespring-floating-client-2.5.0.jar)      | [**Floating Client 2.5.0 Javadoc**](https://licensespring.dream-factory.hr/2.5.0/floating-client/index.html)   | [**Floating Client 2.5.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.5.0/licensespring-floating-client-osgi-2.5.0.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.5.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.5.0/licensespring-license-management-2.5.0.jar) | [**Management SDK 2.5.0 Javadoc**](https://licensespring.dream-factory.hr/2.5.0/license-management/index.html) | [**Management SDK 2.5.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.5.0/licensespring-license-management-osgi-2.5.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.4.16

|                     | Jar                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.16 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.16/licensespring-core-2.4.16.jar)                                       | [**Core 2.4.16 Javadoc**](https://licensespring.dream-factory.hr/2.4.16/core/index.html)                         | [**Core 2.4.16 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.16/licensespring-core-osgi-2.4.16.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.4.16 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.16/licensespring-license-client-2.4.16.jar)         | [**License Client 2.4.16 Javadoc**](https://licensespring.dream-factory.hr/2.4.16/license-client/index.html)     | [**License Client 2.4.16 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.16/licensespring-license-client-osgi-2.4.16.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.4.16 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.16/licensespring-floating-client-2.4.16.jar)      | [**Floating Client 2.4.16 Javadoc**](https://licensespring.dream-factory.hr/2.4.16/floating-client/index.html)   | [**Floating Client 2.4.16 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.4.16/licensespring-floating-client-osgi-2.4.16.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.16 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.16/licensespring-license-management-2.4.16.jar) | [**Management SDK 2.4.16 Javadoc**](https://licensespring.dream-factory.hr/2.4.16/license-management/index.html) | [**Management SDK 2.4.16 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.16/licensespring-license-management-osgi-2.4.16.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.4.15

|                     | Jar                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.15 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.15/licensespring-core-2.4.15.jar)                                       | [**Core 2.4.15 Javadoc**](https://licensespring.dream-factory.hr/2.4.15/core/index.html)                         | [**Core 2.4.15 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.15/licensespring-core-osgi-2.4.15.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.4.15 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.15/licensespring-license-client-2.4.15.jar)         | [**License Client 2.4.15 Javadoc**](https://licensespring.dream-factory.hr/2.4.15/license-client/index.html)     | [**License Client 2.4.15 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.15/licensespring-license-client-osgi-2.4.15.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.4.15 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.15/licensespring-floating-client-2.4.15.jar)      | [**Floating Client 2.4.15 Javadoc**](https://licensespring.dream-factory.hr/2.4.15/floating-client/index.html)   | [**Floating Client 2.4.15 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.4.15/licensespring-floating-client-osgi-2.4.15.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.15 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.15/licensespring-license-management-2.4.15.jar) | [**Management SDK 2.4.15 Javadoc**](https://licensespring.dream-factory.hr/2.4.15/license-management/index.html) | [**Management SDK 2.4.15 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.15/licensespring-license-management-osgi-2.4.15.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.4.14

|                     | Jar                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.14 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.14/licensespring-core-2.4.14.jar)                                       | [**Core 2.4.14 Javadoc**](https://licensespring.dream-factory.hr/2.4.14/core/index.html)                         | [**Core 2.4.14 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.14/licensespring-core-osgi-2.4.14.jar)                                       | 93% classes, 74% lines covered  | 89% classes, 61% methods  |
| **License Client**  | [**License Client 2.4.14 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.14/licensespring-license-client-2.4.14.jar)         | [**License Client 2.4.14 Javadoc**](https://licensespring.dream-factory.hr/2.4.14/license-client/index.html)     | [**License Client 2.4.14 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.14/licensespring-license-client-osgi-2.4.14.jar)         | 100% classes, 80% lines covered | 73% classes, 76% methods  |
| **Floating Client** | [**Floating Client 2.4.14 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.14/licensespring-floating-client-2.4.14.jar)      | [**Floating Client 2.4.14 Javadoc**](https://licensespring.dream-factory.hr/2.4.14/floating-client/index.html)   | [**Floating Client 2.4.14 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.4.14/licensespring-floating-client-osgi-2.4.14.jar)      | 94% classes, 70% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.14 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.14/licensespring-license-management-2.4.14.jar) | [**Management SDK 2.4.14 Javadoc**](https://licensespring.dream-factory.hr/2.4.14/license-management/index.html) | [**Management SDK 2.4.14 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.14/licensespring-license-management-osgi-2.4.14.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.4.13

|                     | Jar                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.13 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.13/licensespring-core-2.4.13.jar)                                       | [**Core 2.4.13 Javadoc**](https://licensespring.dream-factory.hr/2.4.13/core/index.html)                         | [**Core 2.4.13 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.13/licensespring-core-osgi-2.4.13.jar)                                       | 92% classes, 68% lines covered  | 89% classes, 60% methods  |
| **License Client**  | [**License Client 2.4.13 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.13/licensespring-license-client-2.4.13.jar)         | [**License Client 2.4.13 Javadoc**](https://licensespring.dream-factory.hr/2.4.13/license-client/index.html)     | [**License Client 2.4.13 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.13/licensespring-license-client-osgi-2.4.13.jar)         | 100% classes, 80% lines covered | 73% classes, 74% methods  |
| **Floating Client** | [**Floating Client 2.4.13 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.13/licensespring-floating-client-2.4.13.jar)      | [**Floating Client 2.4.13 Javadoc**](https://licensespring.dream-factory.hr/2.4.13/floating-client/index.html)   | [**Floating Client 2.4.13 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.4.13/licensespring-floating-client-osgi-2.4.13.jar)      | 94% classes, 75% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.13 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.13/licensespring-license-management-2.4.13.jar) | [**Management SDK 2.4.13 Javadoc**](https://licensespring.dream-factory.hr/2.4.13/license-management/index.html) | [**Management SDK 2.4.13 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.13/licensespring-license-management-osgi-2.4.13.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.4.12

|                     | Jar                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.12 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.12/licensespring-core-2.4.12.jar)                                       | [**Core 2.4.12 Javadoc**](https://licensespring.dream-factory.hr/2.4.12/core/index.html)                         | [**Core 2.4.12 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.12/licensespring-core-osgi-2.4.12.jar)                                       | 92% classes, 68% lines covered  | 89% classes, 60% methods  |
| **License Client**  | [**License Client 2.4.12 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.12/licensespring-license-client-2.4.12.jar)         | [**License Client 2.4.12 Javadoc**](https://licensespring.dream-factory.hr/2.4.12/license-client/index.html)     | [**License Client 2.4.12 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.12/licensespring-license-client-osgi-2.4.12.jar)         | 100% classes, 80% lines covered | 73% classes, 74% methods  |
| **Floating Client** | [**Floating Client 2.4.12 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.12/licensespring-floating-client-2.4.12.jar)      | [**Floating Client 2.4.12 Javadoc**](https://licensespring.dream-factory.hr/2.4.12/floating-client/index.html)   | [**Floating Client 2.4.12 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.4.12/licensespring-floating-client-osgi-2.4.12.jar)      | 94% classes, 75% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.12 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.12/licensespring-license-management-2.4.12.jar) | [**Management SDK 2.4.12 Javadoc**](https://licensespring.dream-factory.hr/2.4.12/license-management/index.html) | [**Management SDK 2.4.12 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.12/licensespring-license-management-osgi-2.4.12.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.4.11

|                     | Jar                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.11 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.11/licensespring-core-2.4.11.jar)                                       | [**Core 2.4.11 Javadoc**](https://licensespring.dream-factory.hr/2.4.11/core/index.html)                         | [**Core 2.4.11 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.11/licensespring-core-osgi-2.4.11.jar)                                       | 92% classes, 68% lines covered  | 89% classes, 60% methods  |
| **License Client**  | [**License Client 2.4.11 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.11/licensespring-license-client-2.4.11.jar)         | [**License Client 2.4.11 Javadoc**](https://licensespring.dream-factory.hr/2.4.11/license-client/index.html)     | [**License Client 2.4.11 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.11/licensespring-license-client-osgi-2.4.11.jar)         | 100% classes, 80% lines covered | 73% classes, 74% methods  |
| **Floating Client** | [**Floating Client 2.4.11 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.11/licensespring-floating-client-2.4.11.jar)      | [**License Client 2.4.11 Javadoc**](https://licensespring.dream-factory.hr/2.4.11/license-client/index.html)     | [**Floating Client 2.4.11 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.4.11/licensespring-floating-client-osgi-2.4.11.jar)      | 94% classes, 75% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.11 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.11/licensespring-license-management-2.4.11.jar) | [**Management SDK 2.4.11 Javadoc**](https://licensespring.dream-factory.hr/2.4.11/license-management/index.html) | [**Management SDK 2.4.11 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.11/licensespring-license-management-osgi-2.4.11.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.4.10

|                     | Jar                                                                                                                                                                                              | Javadoc                                                                                                          | OSGi bundle                                                                                                                                                                                                 | Test Coverage                   | Javadoc Coverage          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.10 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.10/licensespring-core-2.4.10.jar)                                       | [**Core 2.4.10 Javadoc**](https://licensespring.dream-factory.hr/2.4.10/core/index.html)                         | [**Core 2.4.10 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.10/licensespring-core-osgi-2.4.10.jar)                                       | 92% classes, 68% lines covered  | 89% classes, 60% methods  |
| **License Client**  | [**License Client 2.4.10 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.10/licensespring-license-client-2.4.10.jar)         | [**License Client 2.4.10 Javadoc**](https://licensespring.dream-factory.hr/2.4.10/license-client/index.html)     | [**License Client 2.4.10 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.10/licensespring-license-client-osgi-2.4.10.jar)         | 100% classes, 80% lines covered | 73% classes, 74% methods  |
| **Floating Client** | [**Floating Client 2.4.10 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.10/licensespring-floating-client-2.4.10.jar)      | [**Floating Client 2.4.10 Javadoc**](https://licensespring.dream-factory.hr/2.4.10/floating-client/index.html)   | [**Floating Client 2.4.10 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.4.10/licensespring-floating-client-osgi-2.4.10.jar)      | 94% classes, 75% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.10 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.10/licensespring-license-management-2.4.10.jar) | [**Management SDK 2.4.10 Javadoc**](https://licensespring.dream-factory.hr/2.4.10/license-management/index.html) | [**Management SDK 2.4.10 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.10/licensespring-license-management-osgi-2.4.10.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.4.9

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.9 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.9/licensespring-core-2.4.9.jar)                                       | [**Core 2.4.9 Javadoc**](https://licensespring.dream-factory.hr/2.4.9/core/index.html)                         | [**Core 2.4.9 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.9/licensespring-core-osgi-2.4.9.jar)                                       | 92% classes, 68% lines covered  | 89% classes, 60% methods  |
| **License Client**  | [**License Client 2.4.9 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.9/licensespring-license-client-2.4.9.jar)         | [**License Client 2.4.9 Javadoc**](https://licensespring.dream-factory.hr/2.4.9/license-client/index.html)     | [**License Client 2.4.9 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.9/licensespring-license-client-osgi-2.4.9.jar)         | 100% classes, 80% lines covered | 73% classes, 74% methods  |
| **Floating Client** | [**Floating Client 2.4.9 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.9/licensespring-floating-client-2.4.9.jar)      | [**Floating Client 2.4.9 Javadoc**](https://licensespring.dream-factory.hr/2.4.9/floating-client/index.html)   | [**Floating Client 2.4.9 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.4.9/licensespring-floating-client-osgi-2.4.9.jar)      | 94% classes, 75% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.9 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.9/licensespring-license-management-2.4.9.jar) | [**Management SDK 2.4.9 Javadoc**](https://licensespring.dream-factory.hr/2.4.9/license-management/index.html) | [**Management SDK 2.4.9 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.9/licensespring-license-management-osgi-2.4.9.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.4.8

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.8 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.8/licensespring-core-2.4.8.jar)                                       | [**Core 2.4.8 Javadoc**](https://licensespring.dream-factory.hr/2.4.8/core/index.html)                         | [**Core 2.4.8 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.8/licensespring-core-osgi-2.4.8.jar)                                       | 92% classes, 68% lines covered  | 89% classes, 60% methods  |
| **License Client**  | [**License Client 2.4.8 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.8/licensespring-license-client-2.4.8.jar)         | [**License Client 2.4.8 Javadoc**](https://licensespring.dream-factory.hr/2.4.8/license-client/index.html)     | [**License Client 2.4.8 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.8/licensespring-license-client-osgi-2.4.8.jar)         | 100% classes, 80% lines covered | 73% classes, 74% methods  |
| **Floating Client** | [**Floating Client 2.4.8 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.8/licensespring-floating-client-2.4.8.jar)      | [**Floating Client 2.4.8 Javadoc**](https://licensespring.dream-factory.hr/2.4.8/floating-client/index.html)   | [**Floating Client 2.4.8 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.4.8/licensespring-floating-client-osgi-2.4.8.jar)      | 94% classes, 75% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.8 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.8/licensespring-license-management-2.4.8.jar) | [**Management SDK 2.4.8 Javadoc**](https://licensespring.dream-factory.hr/2.4.8/license-management/index.html) | [**Management SDK 2.4.8 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.8/licensespring-license-management-osgi-2.4.8.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.4.7

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.7 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.7/licensespring-core-2.4.7.jar)                                       | [**Core 2.4.7 Javadoc**](https://licensespring.dream-factory.hr/2.4.7/core/index.html)                         | [**Core 2.4.7 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.7/licensespring-core-osgi-2.4.7.jar)                                       | 92% classes, 68% lines covered  | 89% classes, 60% methods  |
| **License Client**  | [**License Client 2.4.7 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.7/licensespring-license-client-2.4.7.jar)         | [**License Client 2.4.7 Javadoc**](https://licensespring.dream-factory.hr/2.4.7/license-client/index.html)     | [**License Client 2.4.7 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.7/licensespring-license-client-osgi-2.4.7.jar)         | 100% classes, 80% lines covered | 73% classes, 74% methods  |
| **Floating Client** | [**Floating Client 2.4.7 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.7/licensespring-floating-client-2.4.7.jar)      | [**Floating Client 2.4.7 Javadoc**](https://licensespring.dream-factory.hr/2.4.7/floating-client/index.html)   | [**Floating Client 2.4.7 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.4.7/licensespring-floating-client-osgi-2.4.7.jar)      | 94% classes, 75% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.7 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.7/licensespring-license-management-2.4.7.jar) | [**Management SDK 2.4.7 Javadoc**](https://licensespring.dream-factory.hr/2.4.7/license-management/index.html) | [**Management SDK 2.4.7 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.7/licensespring-license-management-osgi-2.4.7.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.4.6

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.6 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.6/licensespring-core-2.4.6.jar)                                       | [**Core 2.4.6 Javadoc**](https://licensespring.dream-factory.hr/2.4.6/core/index.html)                         | [**Core 2.4.6 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.6/licensespring-core-osgi-2.4.6.jar)                                       | 79% classes, 63% lines covered  | 89% classes, 58% methods  |
| **License Client**  | [**License Client 2.4.6 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.6/licensespring-license-client-2.4.6.jar)         | [**License Client 2.4.6 Javadoc**](https://licensespring.dream-factory.hr/2.4.6/license-client/index.html)     | [**License Client 2.4.6 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.6/licensespring-license-client-osgi-2.4.6.jar)         | 100% classes, 81% lines covered | 73% classes, 74% methods  |
| **Floating Client** | [**Floating Client 2.4.6 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.6/licensespring-floating-client-2.4.6.jar)      | [**License Client 2.4.6 Javadoc**](https://licensespring.dream-factory.hr/2.4.6/license-client/index.html)     | [**Floating Client 2.4.6 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.4.6/licensespring-floating-client-osgi-2.4.6.jar)      | 52% classes, 53% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.6 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.6/licensespring-license-management-2.4.6.jar) | [**Management SDK 2.4.6 Javadoc**](https://licensespring.dream-factory.hr/2.4.6/license-management/index.html) | [**Management SDK 2.4.6 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.6/licensespring-license-management-osgi-2.4.6.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.4.5

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                                                                                                       | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.5/licensespring-core-2.4.5.jar)                                       | [**Management SDK 2.4.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.5/licensespring-license-management-2.4.5.jar) | [**Core 2.4.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.5/licensespring-core-osgi-2.4.5.jar)                                       | 79% classes, 63% lines covered  | 89% classes, 58% methods  |
| **License Client**  | [**License Client 2.4.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.5/licensespring-license-client-2.4.5.jar)         | [**License Client 2.4.5 Javadoc**](https://licensespring.dream-factory.hr/2.4.5/license-client/index.html)                                                                                    | [**License Client 2.4.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.5/licensespring-license-client-osgi-2.4.5.jar)         | 100% classes, 81% lines covered | 73% classes, 74% methods  |
| **Floating Client** | [**Floating Client 2.4.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.5/licensespring-floating-client-2.4.5.jar)      | [**Floating Client 2.4.5 Javadoc**](https://licensespring.dream-factory.hr/2.4.5/floating-client/index.html)                                                                                  | [**Floating Client 2.4.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.4.5/licensespring-floating-client-osgi-2.4.5.jar)      | 52% classes, 53% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.5 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.5/licensespring-license-management-2.4.5.jar) | [**Management SDK 2.4.5 Javadoc**](https://licensespring.dream-factory.hr/2.4.5/license-management/index.html)                                                                                | [**Management SDK 2.4.5 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.5/licensespring-license-management-osgi-2.4.5.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version **2.4.4**

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                      | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.4/licensespring-core-2.4.4.jar)                                       | [**Core 2.4.4 Javadoc**](https://licensespring.dream-factory.hr/2.4.4/core/index.html)                       | [**Core 2.4.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.4/licensespring-core-osgi-2.4.4.jar)                                       | 79% classes, 63% lines covered  | 89% classes, 58% methods  |
| **License Client**  | [**License Client 2.4.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.4/licensespring-license-client-2.4.4.jar)         | [**License Client 2.4.4 Javadoc**](https://licensespring.dream-factory.hr/2.4.4/license-client/index.html)   | [**License Client 2.4.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.4/licensespring-license-client-osgi-2.4.4.jar)         | 100% classes, 81% lines covered | 73% classes, 74% methods  |
| **Floating Client** | [**Floating Client 2.4.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.4/licensespring-floating-client-2.4.4.jar)      | [**Floating Client 2.4.4 Javadoc**](https://licensespring.dream-factory.hr/2.4.4/floating-client/index.html) | [**License Client 2.4.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.4/licensespring-license-client-osgi-2.4.4.jar)         | 52% classes, 53% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.4 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.4/licensespring-license-management-2.4.4.jar) | [**Floating Client 2.4.4 Javadoc**](https://licensespring.dream-factory.hr/2.4.4/floating-client/index.html) | [**Management SDK 2.4.4 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.4/licensespring-license-management-osgi-2.4.4.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.4.3

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.3/licensespring-core-2.4.3.jar)                                       | [**Core 2.4.3 Javadoc**](https://licensespring.dream-factory.hr/2.4.3/core/index.html)                         | [**Core 2.4.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.3/licensespring-core-osgi-2.4.3.jar)                                       | 79% classes, 63% lines covered  | 89% classes, 58% methods  |
| **License Client**  | [**License Client 2.4.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.3/licensespring-license-client-2.4.3.jar)         | [**License Client 2.4.3 Javadoc**](https://licensespring.dream-factory.hr/2.4.3/license-client/index.html)     | [**License Client 2.4.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.3/licensespring-license-client-osgi-2.4.3.jar)         | 100% classes, 81% lines covered | 73% classes, 74% methods  |
| **Floating Client** | [**Floating Client 2.4.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.3/licensespring-floating-client-2.4.3.jar)      | [**Floating Client 2.4.3 Javadoc**](https://licensespring.dream-factory.hr/2.4.3/floating-client/index.html)   | [**Floating Client 2.4.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.4.3/licensespring-floating-client-osgi-2.4.3.jar)      | 52% classes, 53% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.3 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.3/licensespring-license-management-2.4.3.jar) | [**Management SDK 2.4.3 Javadoc**](https://licensespring.dream-factory.hr/2.4.3/license-management/index.html) | [**Management SDK 2.4.3 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.3/licensespring-license-management-osgi-2.4.3.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.4.2

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.2/licensespring-core-2.4.2.jar)                                       | [**Core 2.4.2 Javadoc**](https://licensespring.dream-factory.hr/2.4.2/core/index.html)                         | [**Core 2.4.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.2/licensespring-core-osgi-2.4.2.jar)                                       | 79% classes, 63% lines covered  | 89% classes, 58% methods  |
| **License Client**  | [**License Client 2.4.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.2/licensespring-license-client-2.4.2.jar)         | [**License Client 2.4.2 Javadoc**](https://licensespring.dream-factory.hr/2.4.2/license-client/index.html)     | [**License Client 2.4.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.2/licensespring-license-client-osgi-2.4.2.jar)         | 100% classes, 81% lines covered | 73% classes, 74% methods  |
| **Floating Client** | [**Floating Client 2.4.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.2/licensespring-floating-client-2.4.2.jar)      | [**Floating Client 2.4.2 Javadoc**](https://licensespring.dream-factory.hr/2.4.2/floating-client/index.html)   | [**Floating Client 2.4.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.4.2/licensespring-floating-client-osgi-2.4.2.jar)      | 52% classes, 53% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.2/licensespring-license-management-2.4.2.jar) | [**Management SDK 2.4.2 Javadoc**](https://licensespring.dream-factory.hr/2.4.2/license-management/index.html) | [**Management SDK 2.4.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.2/licensespring-license-management-osgi-2.4.2.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.4.1

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.1/licensespring-core-2.4.1.jar)                                       | [**Core 2.4.1 Javadoc**](https://licensespring.dream-factory.hr/2.4.1/core/index.html)                         | [**Core 2.4.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.1/licensespring-core-osgi-2.4.1.jar)                                       | 79% classes, 63% lines covered  | 89% classes, 58% methods  |
| **License Client**  | [**License Client 2.4.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.1/licensespring-license-client-2.4.1.jar)         | [**License Client 2.4.1 Javadoc**](https://licensespring.dream-factory.hr/2.4.1/license-client/index.html)     | [**License Client 2.4.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.1/licensespring-license-client-osgi-2.4.1.jar)         | 100% classes, 81% lines covered | 73% classes, 74% methods  |
| **Floating Client** | [**Floating Client 2.4.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.1/licensespring-floating-client-2.4.1.jar)      | [**Floating Client 2.4.1 Javadoc**](https://licensespring.dream-factory.hr/2.4.1/floating-client/index.html)   | [**Floating Client 2.4.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.4.1/licensespring-floating-client-osgi-2.4.1.jar)      | 52% classes, 53% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.1/licensespring-license-management-2.4.1.jar) | [**Management SDK 2.4.1 Javadoc**](https://licensespring.dream-factory.hr/2.4.1/license-management/index.html) | [**Management SDK 2.4.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.1/licensespring-license-management-osgi-2.4.1.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.4.0

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage          |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------- |
| **Core**            | [**Core 2.4.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.4.0/licensespring-core-2.4.0.jar)                                       | [**Core 2.4.0 Javadoc**](https://licensespring.dream-factory.hr/2.4.0/core/index.html)                         | [**Core 2.4.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.4.0/licensespring-core-osgi-2.4.0.jar)                                       | 79% classes, 63% lines covered  | 89% classes, 58% methods  |
| **License Client**  | [**License Client 2.4.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.4.0/licensespring-license-client-2.4.0.jar)         | [**License Client 2.4.0 Javadoc**](https://licensespring.dream-factory.hr/2.4.0/license-client/index.html)     | [**License Client 2.4.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.4.0/licensespring-license-client-osgi-2.4.0.jar)         | 100% classes, 81% lines covered | 73% classes, 74% methods  |
| **Floating Client** | [**Floating Client 2.4.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.4.0/licensespring-floating-client-2.4.0.jar)      | [**Floating Client 2.4.0 Javadoc**](https://licensespring.dream-factory.hr/2.4.0/floating-client/index.html)   | [**Floating Client 2.4.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.4.0/licensespring-floating-client-osgi-2.4.0.jar)      | 52% classes, 53% lines covered  | 100% classes, 95% methods |
| **Management SDK**  | [**Management SDK 2.4.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.4.0/licensespring-license-management-2.4.0.jar) | [**Management SDK 2.4.0 Javadoc**](https://licensespring.dream-factory.hr/2.4.0/license-management/index.html) | [**Management SDK 2.4.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.4.0/licensespring-license-management-osgi-2.4.0.jar) | 94% classes, 67% lines covered  | 100% classes, 83% methods |

### Version 2.3.2

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage         |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------ |
| **Core**            | [**Core 2.3.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.3.2/licensespring-core-2.3.2.jar)                                       | [**Core 2.3.2 Javadoc**](https://licensespring.dream-factory.hr/2.3.2/core/index.html)                         | [**Core 2.3.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.3.2/licensespring-core-osgi-2.3.2.jar)                                       | 89% classes, 67% lines covered  | 89% classes, 54% methods |
| **License Client**  | [**License Client 2.3.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.3.2/licensespring-license-client-2.3.2.jar)         | [**License Client 2.3.2 Javadoc**](https://licensespring.dream-factory.hr/2.3.2/license-client/index.html)     | [**License Client 2.3.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.3.2/licensespring-license-client-osgi-2.3.2.jar)         | 100% classes, 73% lines covered | 73% classes, 74% methods |
| **Floating Client** | [**Floating Client 2.3.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.3.2/licensespring-floating-client-2.3.2.jar)      | [**Floating Client 2.3.2 Javadoc**](https://licensespring.dream-factory.hr/2.3.2/floating-client/index.html)   | [**Floating Client 2.3.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.3.2/licensespring-floating-client-osgi-2.3.2.jar)      | 87% classes, 68% lines covered  | 88% classes, 96% methods |
| **Management SDK**  | [**Management SDK 2.3.2 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.3.2/licensespring-license-management-2.3.2.jar) | [**Management SDK 2.3.2 Javadoc**](https://licensespring.dream-factory.hr/2.3.2/license-management/index.html) | [**Management SDK 2.3.2 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.3.2/licensespring-license-management-osgi-2.3.2.jar) | 85% classes, 48% lines covered  | 83% classes, 71% methods |

### Version 2.3.1

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage         |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------ |
| **Core**            | [**Core 2.3.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.3.1/licensespring-core-2.3.1.jar)                                       | [**Core 2.3.1 Javadoc**](https://licensespring.dream-factory.hr/2.3.1/core/index.html)                         | [**Management SDK 2.3.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.3.1/licensespring-license-management-osgi-2.3.1.jar) | 90% classes, 68% lines covered  | 89% classes, 54% methods |
| **License Client**  | [**License Client 2.3.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.3.1/licensespring-license-client-2.3.1.jar)         | [**License Client 2.3.1 Javadoc**](https://licensespring.dream-factory.hr/2.3.1/license-client/index.html)     | [**Floating Client 2.3.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.3.1/licensespring-floating-client-osgi-2.3.1.jar)      | 100% classes, 77% lines covered | 73% classes, 74% methods |
| **Floating Client** | [**Floating Client 2.3.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.3.1/licensespring-floating-client-2.3.1.jar)      | [**Floating Client 2.3.1 Javadoc**](https://licensespring.dream-factory.hr/2.3.1/floating-client/index.html)   | [**License Client 2.3.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.3.1/licensespring-license-client-osgi-2.3.1.jar)         | 87% classes, 68% lines covered  | 88% classes, 96% methods |
| **Management SDK**  | [**Management SDK 2.3.1 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.3.1/licensespring-license-management-2.3.1.jar) | [**Management SDK 2.3.1 Javadoc**](https://licensespring.dream-factory.hr/2.3.1/license-management/index.html) | [**Core 2.3.1 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.3.1/licensespring-core-osgi-2.3.1.jar)                                       | 85% classes, 48% lines covered  | 83% classes, 71% methods |

### Version 2.3.0

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   | Javadoc Coverage         |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------ |
| **Core**            | [**Core 2.3.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.3.0/licensespring-core-2.3.0.jar)                                       | [**Core 2.3.0 Javadoc**](https://licensespring.dream-factory.hr/2.3.0/core/index.html)                         | [**Core 2.3.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.3.0/licensespring-core-osgi-2.3.0.jar)                                       | 89% classes, 67% lines covered  | 89% classes, 54% methods |
| **License Client**  | [**License Client 2.3.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.3.0/licensespring-license-client-2.3.0.jar)         | [**License Client 2.3.0 Javadoc**](https://licensespring.dream-factory.hr/2.3.0/license-client/index.html)     | [**License Client 2.3.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.3.0/licensespring-license-client-osgi-2.3.0.jar)         | 100% classes, 73% lines covered | 73% classes, 74% methods |
| **Floating Client** | [**Floating Client 2.3.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.3.0/licensespring-floating-client-2.3.0.jar)      | [**Floating Client 2.3.0 Javadoc**](https://licensespring.dream-factory.hr/2.3.0/floating-client/index.html)   | [**Floating Client 2.3.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.3.0/licensespring-floating-client-osgi-2.3.0.jar)      | 87% classes, 68% lines covered  | 88% classes, 96% methods |
| **Management SDK**  | [**Management SDK 2.3.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.3.0/licensespring-license-management-2.3.0.jar) | [**Management SDK 2.3.0 Javadoc**](https://licensespring.dream-factory.hr/2.3.0/license-management/index.html) | [**Management SDK 2.3.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.3.0/licensespring-license-management-osgi-2.3.0.jar) | 85% classes, 48% lines covered  | 83% classes, 71% methods |

### Version 2.2.0

|                     | Jar                                                                                                                                                                                           | Javadoc                                                                                                        | OSGi bundle                                                                                                                                                                                              | Test Coverage                   |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- |
| **Core**            | [**Core 2.2.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core/2.2.0/licensespring-core-2.2.0.jar)                                       | [**Core 2.2.0 Javadoc**](https://licensespring.dream-factory.hr/2.2.0/core/index.html)                         | [**Core 2.2.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-core-osgi/2.2.0/licensespring-core-osgi-2.2.0.jar)                                       | 88% classes, 68% lines covered  |
| **License Client**  | [**License Client 2.2.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client/2.2.0/licensespring-license-client-2.2.0.jar)         | [**License Client 2.2.0 Javadoc**](https://licensespring.dream-factory.hr/2.2.0/license-client/index.html)     | [**License Client 2.2.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-client-osgi/2.2.0/licensespring-license-client-osgi-2.2.0.jar)         | 100% classes, 69% lines covered |
| **Floating Client** | [**Floating Client 2.2.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client/2.2.0/licensespring-floating-client-2.2.0.jar)      | [**Floating Client 2.2.0 Javadoc**](https://licensespring.dream-factory.hr/2.2.0/floating-client/index.html)   | [**Floating Client 2.2.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-floating-client-osgi/2.2.0/licensespring-floating-client-osgi-2.2.0.jar)      | 88% classes, 45% lines covered  |
| **Management SDK**  | [**Management SDK 2.2.0 Jar**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management/2.2.0/licensespring-license-management-2.2.0.jar) | [**Management SDK 2.2.0 Javadoc**](https://licensespring.dream-factory.hr/2.2.0/license-management/index.html) | [**Management SDK 2.2.0 OSGi**](https://licensespring-maven.s3.eu-central-1.amazonaws.com/com/licensespring/licensespring-license-management-osgi/2.2.0/licensespring-license-management-osgi-2.2.0.jar) | 62% classes, 40% lines covered  |


[title] Device Variables Usage
[path] SDKs/Tutorials/Best Practices/

Device variables play a crucial role in LicenseSpring's SDKs by facilitating the exchange of data from devices to the vendor platform.

This mechanism allows developers and administrators to gather real-time device-specific information, empowering them to make informed decisions and tailor licensing strategies based on accurate insights.

The aim of this section is to provide you with a comprehensive understanding of effectively utilizing device variables.

::embed[]{url="https://www.youtube.com/watch?v=qvsAqdnxvmo&t=2s&ab_channel=LicenseSpringSoftware"}

## Prerequisites

1. Completed the [**Getting Started**](docId\:LSFY9tQ3vfq4ROOW9sHkd) Tutorial, including:
   - Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
   - Created a `LicenseID` using either `LicenseID::fromKey` or `LicenseID::fromUser` function, depending on the activation method you prefer.
   - Activated a license of any type.
   - Implemented routine local and online checks within the application.&#x20;

## Understanding Device Variable Usage

Some examples of scenarios where device variables are useful:

### Hardware Specifications

Device variables can be utilized to capture and transmit hardware specifications, such as CPU type, RAM size, and storage capacity.&#x20;

This information can be invaluable for tailoring licenses based on the user's hardware capabilities.

### Tracking User Registration Data

User registration data includes names and user information, which can be sent and kept track of on the LicenseSpring platform using these variables.&#x20;

This enables you to gather and manage essential user details directly within the licensing framework, streamlining administrative tasks and enhancing user experience.

### User Preferences:

Store user preferences, settings, and configurations using device variables to create a more personalized and seamless user experience.

## Adding Device Variables

Integrating device variables is simple with the LicenseSpring SDK, and on existing licenses can be done in three different ways:

1. Adding a name-value pair
2. Adding a `DeviceVariable` object
3. Adding multiple `DeviceVariable` objects via vector/array.

:::CodeblockTabs
```cpp
//1.
license->addDeviceVariable( "Name", "Value", false );
//2. 
DeviceVariable deviceVar = DeviceVariable( "Name", "Value");
license->addDeviceVariable( deviceVar, false );
//3.
std::vector<DeviceVariable> deviceVariables = { DeviceVariable( "Name1", "Value1" ), DeviceVariable( "Name2", "Value2" ) };
license->addDeviceVariables( deviceVariables );

//Finally, to send our variables to the LicenseSpring server:
license->sendDeviceVariables();
```

```csharp
//1.
license.AddDeviceVariable("Name", "Value");
//2.
DeviceVariable deviceVariable = DeviceVariable("Name", "Value");
license.AddDeviceVariable(deviceVar);
//3.
DeviceVariable[] devVariables = { new DeviceVariable( "name1", "value1" ), 
                                  new DeviceVariable( "name2", "value2" ) };
license.AddDeviceVariables(devVariables);

//Finally, to send our variables to the LicenseSpring server:
license.SendDeviceVariables();
```

Swift

```swift
try license.sendDeviceVariables([
    "Name1": "Value1",
    "Name2": "Value2"
])
```

```python
# 1,2,3 are directly supported within set_device_variables

license.set_device_variables({"a":"b","c":"d"})

#send device variables to LS server
license.send_device_variables()

```

```go
// Go SDK v2
	customFields := []core_request.CustomFields{}
	customFields = append(customFields, core_request.CustomFields{Name: "name", Value: "device1"})
	err = lh.SendDeviceData(ctx, customFields)

```

```java
String licenseKey = "<SAMPLE-KEY>";
String licenseIdentity = LicenseIdentity.fromKey(licenseKey);
DeviceVariables variables = DeviceVariables.builder()
  .variable("var1", "value1")
  .variable("var2", "value2")
  .build();

licenseManager.trackVariables(licenseIdentity, variables.getVariables());
```

```javascript
const license = licenseManager.loadLicense();
// the following sets the variables on the license object; 
// the second (boolean) parameter determines whether to save the changes to the license file:
license.setDeviceVariablesLocal({ key1: 'value1' }, true);
// the following syncs the updated device variables with the server;
// the boolean parameter determines whether to save the changes to the license file:
license.setDeviceVariables(true);
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x54;o update a device variable, you can simply add the device variable with the same name, and it’s updated value.
:::

Device variables can also be set on license activation:

:::CodeblockTabs
```csharp
DeviceVariable[] deviceVariables = { new DeviceVariable("name1", "value1"),
                                     new DeviceVariable("name2", "value2") };
LicenseID id = LicenseID.FromKey("license-key-goes-here");
ILicense license = licenseManager.ActivateLicense(id, deviceVariables);

// Offline activation is also supported.
string offlineActivationFile = licenseManager.GetOfflineActivationFile(id, deviceVariables);
```

```cpp
std::vector<DeviceVariable> deviceVariables = { {"name1", "value1"}, {"name2", "value2"} };
auto licenseId = LicenseID::fromKey("license-key-here");

auto license = licenseManager->activateLicense(licenseId, deviceVariables)

// Offline activation is also supported.
std::wstring offlineActivationFile = licenseManager->createOfflineActivationFile(licenseId, deviceVariables);
```

```python
# Only supports offline acitvations
req_folder = "req_folder_path"

lm.create_offline_activation_file(license_id,req_folder,device_variables={"a":"b","c":"d"})


```

```java
String licenseKey = "<SAMPLE-KEY>";
String licenseIdentity = LicenseIdentity.fromKey(licenseKey);
DeviceVariables variables = DeviceVariables.builder()
  .variable("var1", "value1")
  .variable("var2", "value2")
  .build();

ActivateOfflineParams params = ActivateOfflineParams
  .builder()
  .variables(variables)
  .build();
  
String file = licenseManager.offlineActivationFile(licenseIdentity, null, params);
```

```javascript
const offlineActivationPayload = licenseManager.createOfflineActivationPayload({ variables: { key1: 'value1' } });
```
:::

## Accessing Device Variables

To locate the device variables through the vendor platform, first navigate to your license then to the "Devices" tab.&#x20;

![Device tab where device variables are found.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/WT7jjvd_aKYUEqAXYMw6A_image.png "Device tab where device variables are found.")

Next, click on the device variables button to open a list of the device's device variables.

![Device Variables button](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/epit_1zjtoz4mnMMBKn_N_image.png "Device Variables button")

:::CodeblockTabs
```cpp
std::vector<DeviceVariable> device_vec = license->getDeviceVariables( true );
```

```csharp
DeviceVariable[] devVariables = license.GetDeviceVariables( true );
```

Swift

```swift
// Just assess variables (updated after latest online check).
let existingVariables = license.deviceVariables

// Request variables from the LicenseSpring platform.
let updatedVariables = try license.requestDeviceVariables()
```

```python
device_var_list = license.get_device_variables(get_from_be=True)  

print(device_var_list)
```

```go
// Go SDK v2
vars, err := lh.GetDeviceVariables(ctx, true)
```

```java
// Offline: Retrieve Device Variables
License license = licenseManager.getCurrent();
LicenseData data = license.getData();
List<DeviceVariable> variables = data.getVariables();

// Online: Retrieve Device Variables
LicenseIdentity identity = license.getIdentity();
List<DeviceVariable> variables = licenseManager.getVariables(identity);
```

```javascript
const license = licenseManager.loadLicense();
// the following line syncs device variables by fetching them from the server
await license.getDeviceVariables();
const variables = license.getDeviceVariablesLocal();
```
:::

:::hint{type="info"}
**Note:** The SDKs have the ability to retrieve device variables from either the local license or from the backend. The Boolean that is passed as the parameter into the `getDeviceVariables` function decides where they are retrieved from.

`True` gets the device variables from the backend, whereas `False` searches the local license.

By default, this false is set to false. **If no parameters are passed to this method, it will retrieve from the local license.**
:::


[title] Floating Features
[path] SDKs/Tutorials/Licensing Scenarios/

Similar to [**Floating Licenses**](https://docs.licensespring.com/license-entitlements/floating-licenses), LicenseSpring supports [**Floating features**](https://docs.licensespring.com/floating-features).

In this guide you can find an overview of the floating features functionality: registering and releasing floating features and setting up the Floating Features Watchdog.

### Check if a feature is floating

As with floating licenses, you can check if a feature is floating using properties for cloud, as well as offline floating features.
To start, use the following code to check if a license feature is floating:

:::CodeblockTabs
```csharp
foreach (ILicenseFeature licenseFeature in license.Features())
{
  if(licenseFeature.IsFloating || licenseFeature.IsOfflineFloating)
  {
    // DO SOMETHING WITH A FLOATING FEATURE
  }
}
```

C++

```cpp
for( const auto& feature : license->features() )
{
    if( feature.isFloating() || feature.isOfflineFloating() )
    {
        // DO SOMETHING WITH A FLOATING FEATURE
    }
}
```

```python
## add getters
for feature in license.features():
    feature_data = get_feature_data(feature)
    if feature_data["is_floating"] or feature_data["is_floating_cloud"]
```

```java
LicenseData data = license.getData();
List<LicenseFeature> features = data.getProductFeatures();

for (LicenseFeature feature : features) {
  if (feature.isFloating() || feature.isFloatingCloud()) {
    // Do something with a floating feature...
  }
}

```

```swift
for feature in license.features {
    if feature.isFloating || feature.isOfflineFloating {
        // DO SOMETHING WITH A FLOATING FEATURE
    }
}
```
:::

### Floating slots

Developers will want to know the maximum number of users that can simultaneously use a floating feature and the current number of users using the feature. That can be done with:

:::CodeblockTabs
```csharp
uint maxUsers = licenseFeature.FloatingSlotsCount;
uint currentUsers = licenseFeature.FloatingSlotsInUse;
```

```cpp
int32_t maxUsers = feature.floatingUsers()
int32_t currentUsers = feature.floatingInUseCount();
```

```python
feature_lkprod1f1fc1 = license.get_feature_data("lkprod1f1fc1")

feature_lkprod1f1fc1["floating_timeout"] # if feature is floating type
feature_lkprod1f1fc1["floating_users"] # if feature is floating type
```

```java
Long floatingTimeout = feature.getFloatingTimeout();
Long floatingUsers = feature.getFloatingUsers();
```

```swift
let floatingTimeout = feature.floatingTimeout
let floatingUsers = feature.floatingInUseCount
```
:::

### Floating timeout

You can get information on the floating feature timeout (in minutes) and the point in time until which a registered feature is valid (time of registration + floating feature timeout). After that time, LicenseSpring server will automatically release the feature - if it's not registered again.

:::CodeblockTabs
```csharp
uint floatingTimeout = license.FloatingTimeout;
DateTime floatingEndDateTime = license.FloatingEndDateTime;
DateTime floatingEndDateTimeUtc = license.FloatingEndDateTimeUtc;
```

```cpp
int32_t floatingTimeout = feature.floatingTimeout();
tm floatingEndDateTime = feature.floatingEndDateTime();
tm floatingEndDateTimeUtc = feature.floatingEndDateTimeUtc();
```

```python
feature_lkprod1f1fc1 = license.get_feature_data("lkprod1f1fc1")

feature_lkprod1f1fc1["floating_timeout"]
feature_lkprod1f1fc1["floating_end_date"]
feature_lkprod1f1fc1["floating_start_date"]
```

```java
Long floatingTimeout = feature.getFloatingTimeout();
```

```swift
let floatingTimeout = license.floatingTimeout
let floatingEndDate = license.floatingEndDate
```
:::

### Registering and releasing floating features

Similar to floating licenses, floating features have to be periodically registered on the server for them to take up a floating slot.

:::CodeblockTabs
```csharp
ILicenseManager licenseManager = LicenseManager.GetInstance();
ILicense license = licenseManager.CurrentLicense();
ILicenseFeature feature = license.Features().First(e => e.IsFloating);
license.RegisterFloatingFeature(feature);
// You can find a similar sample in the console sample app 
// that is a part of the SDK.
```

```cpp
auto licenseManager = LicenseManager::create( pConfiguration );
auto license = licenseManager->getCurrentLicense();
auto feature = license->features().front();
license->registerFloatingFeature( feature.code() );

// You can find a similar sample in CppSample 
// if you wish not to add the feature to the watchdog, License::registerFloatingFeature has an optional `addToWatchdog` bool parameter.
```

```python
license.check_feature("feature_code")
```

```go
// Go SDK v2
ld, err = lh.CheckLicenseFeature(ctx, featureCode)
```

```java
LicenseIdentity identity = LicenseIdentity.fromKey("<LICENSE-KEY>");
String featureCode = "<FEATURE-CODE>";
service.checkLicenseFeature(identity, featureCode)
```

```swift
let floatingFeature = license.features.filter { $0.isFloating || $0.isOfflineFloating }.first!
try license.registerFloatingFeature(floatingFeature)
```
:::

:::hint{type="danger"}
Note that in the C++ SDK you need to pass the feature code instead of the feature object to `License::registerFloatingFeature`
:::

&#x20;Likewise, if you wish to release a feature before its timeout, you can do it like so:

:::CodeblockTabs
```csharp
ILicenseManager licenseManager = LicenseManager.GetInstance();
ILicense license = licenseManager.CurrentLicense();
ILicenseFeature feature = license
                           .Features()
                           .First(e => e.FloatingEndDateTime > DateTime.Now);
license.ReleaseFloatingFeature(feature);
// You can find a similar sample in the console sample app 
// that is a part of the SDK.
```

```cpp
auto licenseManager = LicenseManager::create( pConfiguration );
auto license = licenseManager->getCurrentLicense();
auto feature = license->features().front();
license->releaseFloatingFeature( feature.code() );
```

```python
license.release_feature("lkprod1f1fc1")
```

```go
ld, err = lh.ReleaseFloatingLicenseFeature(ctx, featureCode)
```

```java
LicenseIdentity identity = LicenseIdentity.fromKey("<LICENSE-KEY>");
String featureCode = "<FEATURE-CODE>";
service.releaseFloatingFeature(identity, featureCode);
```

```swift
let floatingFeature = license.features.filter { $0.isFloating || $0.isOfflineFloating }.first!
license.ReleaseFloatingFeature(feature)
```
:::

:::hint{type="danger"}
In .NET SDK, ILicenseFeature data is not refreshed after registering and releasing the feature. In order to get updated values like FloatingSlotsInUse and FloatingEndDateTime you have to call ILicense.Features() method again.

The same applies to the C++ SDK. You have to call license->features() again to get updated feature values.
:::

### Watchdog setup

Similar to a [**floating license watchdog,**](https://docs.licensespring.com/sdks/tutorials/licensing-scenarios/floating#PBfrR) floating features have to initialize the watchdog in order to use its functionalities.

Once configured, floating features only need to be registered once. The watchdog ensures they remain active until they are manually released. Be sure to release them when the application shuts down to free up the slots.

You initialize the watchdog like so:

:::CodeblockTabs
```csharp
void WatchdogCallbackMethod(LicenseSpringException e)
{
  // DO SOMETHING
}

license.SetupFloatingFeatureWatchdog(WatchdogCallbackMethod);

// Callback method will be invoked only if an exception in a watchdog thread
// is raised. If you want to invoke the callback on every feature
// registration you can pass an optional parameter to the method:
license.SetupFloatingFeatureWatchdog(WatchdogCallbackMethod, true);
```

```cpp
void watchdogCallback( const LicenseSpringException& ex )
{
  // DO SOMETHING
}

license->setupFeatureWatchdog( watchdogCallback );
```

```python
license.setup_feature_watch_dog(callback,timeout)
```

```java
FloatingConfiguration config = FloatingConfiguration.builder()
  .enableFloatingFeaturePeriodicCheck(true)
  .build();
```

```swift
typealias LicenseWatchdogCallback = (LSError?) -> Void

license.setupFloatingFeatureWatchdog(callback: { error in
    //do something
}, runCallbackOnEveryCheck: true)
```
:::

Setting up the watchdog will also start the thread. If you wish to stop automatically extending your floating features, you can stop the watchdog:

:::CodeblockTabs
```csharp
license.StopFloatingFeatureWatchdog();
```

```cpp
license->stopFeatureWatchdog();
```

```python
license.stop_feature_watch_dog()
```

```swift
license.stopFloatingFeatureWatchdog()
```
:::

And once stoped, it can be restarted again:

:::CodeblockTabs
```csharp
license.StartFloatingFeatureWatchdog();
```

```cpp
license->resumeFeatureWatchdog();
```

```swift
license.startFloatingFeatureWatchdog();
```
:::






[title] Floating Licensing
[path] SDKs/Tutorials/Licensing Scenarios/

LicenseSpring enables developers to generate licenses for concurrent usage among application users, using LicenseSpring as the floating license server.&#x20;

See [**Floating Licenses**](docId:4aUNyPIaL8I2te4NypPx7) for more information about floating licensing.

This guide offers a fundamental overview of how to leverage the floating cloud functionality. This includes instructions on how to register and deregister a floating cloud license, manage timeouts, and implement license borrowing.

By the end of this tutorial, readers will understand when to use floating licenses and how to implement handling of a cloud floating license within their applications.

## Prerequisites

Completed the Getting Started tutorials, specifically:

- Initialized LicenseManager (or LicenseHandler) with your configuration using the appropriate settings.
- Activated a license.

## Creating a Floating License

The default maximum simultaneous license users and floating timeout period are setting during product creation.

![Selecting floating cloud and setting timeout and max simultaneous users](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/jnoZUUt8CQDaHxLx4DZAV_image.png "Selecting floating cloud and setting timeout and max simultaneous users")

It is also possible to edit these default values when issuing a license.

![Editing default values when issuing license.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/3uGoHvmg1Bhp0jbCELUpN_image.png "Editing default values when issuing license.")

## Floating License Data

Floating licenses encompass a multitude of distinctive fields that are specific to this licensing model. These fields are tailored to the dynamic nature of floating licenses and are designed to cater to the flexible allocation, sharing, and management of software licenses across multiple users and devices.&#x20;

### Checking if a License is Floating

First, developers are able to check whether a license is floating using the following:

:::CodeblockTabs
```cpp
if ( license->isFloating() )
  //License is floating
```

```csharp
if ( licenses.IsFloating() )
  //License is floating
```

```swift
license.isFloating
```

```python
if license.is_floating():
    pass
```

```java
LicenseData data = license.getData();
if (data.isFloating()) {
  // license is floating
}
```
:::

### Checking Maximum Floating Users

Our SDKs offer the ability to check the maximum simultaneous license users with:

:::CodeblockTabs
```cpp
license->maxFloatingUsers();
```

```csharp
license.FloatingSlotsCount();
```

```swift
license.maxFloatingUsers
```

```python
license.max_floating_users()
```

```java
license.getFloatingUsers();
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x4F;nly query this value after online license check or registration (for offline floating).
:::

:::hint{type="danger"}
If this value is reached and another 'checkout' is attempted, our SDKs will throw a **MaxFloatingReachedException**.
:::

### Retrieving Number of Floating Licenses in Use

Our .NET and C++ SDKs also allow developers to check the number of floating licenses currently in use with:

:::CodeblockTabs
```cpp
license->floatingInUseCount();
```

```csharp
license.FloatingSlotsInUse();
```

```swift
license.floatingInUseCount
```

```python
license.floating_in_use_devices()
```

```java
license.getFloatingInUseDevices();
```
:::

### Floating Timeout

The Floating Timeout determines the timeout duration for a floating license in minutes. The SDK doesn't refresh the floating license when it times out by default. To enable this feature, set up the floating license watchdog.

The Floating Timeout and floating license validity end date time (in local time and UTC) can be fetched with:

:::CodeblockTabs
```cpp
//Floating timeout:
license->floatingTimeout();
//End Date Time:
license->floatingEndDateTime();
license->floatingEndDateTimeUtc();
```

```csharp
//Floating timeout:
license.FloatingTimeout();
//End Date Time:
license.FloatingEndDateTime();
license.FloatingEndDateTimeUtc();
```

```swift
license.floatingTimeout
license.floatingEndDate
```

```python
license.floating_timeout()
```

```java
FloatingConfiguration config = FloatingConfiguration.builder()
  .enablePeriodicCheck(true)
  .build();
```
:::

## Registering a License

In contrast to a floating server setup, a floating cloud license demands individual activation on every device aiming to utilize the license.&#x20;

Therefore, when establishing your floating cloud license arrangement, it is strongly advised to align the "max activations" parameter with or exceed the count specified in the "max simultaneous license users" field.&#x20;

After activation, the registration process through the SDK becomes straightforward. You have the choice of employing the dedicated registration method or conducting an online check, both of which serve to register your access to the floating cloud license.

:::CodeblockTabs
```cpp
auto license = licenseManager->getCurrentLicense();

license->registerFloatingLicense(); 
//OR 
license->check();
```

```csharp
var license = licenseManager.CurrentLicense();

license.registerFloatingLicense();
//Csharp does not have a dedicated register function. Use check instead.
license.Check(); 
```

```java
License license = licenseManager.getCurrent();

//Java does not have a dedicated register function. Use check instead
license = licenseManager.checkLicense( license ); 
```

```swift
try license.registerFloatingLicense()
```

```python
license = manager.load_license()
license.check()
```
:::

:::hint{type="danger"}
Local checks in the C++ and .NET SDKs, since they are routinely called, confirm that a floating license timeout or borrowing period has not expired. If one of them have expired, the local check throws a **FloatingTimeoutExpiredException**.&#x20;
:::

## Watchdog Setup

While conventional floating timeouts can suit certain applications, they necessitate manual implementation of checks and register API calls within the codebase.&#x20;

A case in point is when developers embed online checks for each feature in the code. If a user refrains from utilizing any features for a specific duration, they are timed out and their license is relinquished back to the license pool.&#x20;

Nevertheless, a more practical approach involves the setup of a background thread, which functions perpetually at set intervals to conduct online checks.&#x20;

This method ensures proactive license validation, enhancing user experience by eliminating the need for active feature usage and preventing unintended timeouts

:::CodeblockTabs
```cpp
license->setupLicenseWatchdog( callback, timeout );
```

```csharp
license.SetupLicenseWatchdog( callback, timeout );
//Using LicenseWatchdogSettings class:
license.SetupLicenseWatchdog( watchdogSettings );
```

```java
//In java, this feature needs to be turned on within the configuration object using .enablePeriodicCheck() and .checkPeriod(timeout)
LicenseSpringConfiguration configuration = LicenseSpringConfiguration.builder()
                .apiKey( APIKey )
                .productCode( ProductCode ) 
                .sharedKey( SharedKey )
                .appName( AppName )
                .appVersion( AppVersion )
                .enablePeriodicCheck( true )
                .checkPeriod( timeout )
                .build();
```

```python
license.setup_license_watch_dog(callback,timeout)
```

```none
typealias LicenseWatchdogCallback = (LSError?) -> Void

license.setupLicenseWatchdog({ error in
    //DO SOMETHING
}, timeout: 2)
```
:::

:::hint{type="info"}
**Note:** The parameters in the `setupLicenseWatchdog()` method consist of the callback function that will be called back in case off errors, and the timeout in minutes (which is how often online checks are performed).
:::

In the .NET SDK, there is a class, `LicenseWatchdogSettings`, that holds the settings of the license watchdog and can be used as the lone parameter.

The `LicenseWatchdogSettings` class consists of the following properties:

- `HandleNoInternet` - Boolean that indicates if you want to run license checks more often if `NetworkException` or `LicenseServerException` are encountered.
- `NoInternetTimeout` - Custom watchdog timeout in seconds for the case if `NetworkException` or `LicenseServerException` are encountered.
- `RunCallbackOnEveryCheck` - Boolean that indicates if you want to run the callback after every check.
- `Timeout` - timeout in minutes, 0 means use default.
- `WatchdogCallback` - `LicenseWatchdogCallback` object, which is a function to be called in case of errors or after every check.

:::hint{type="danger"}
**WatchdogException&#x20;**&#x63;alled if watchdog thread cannot be started.
:::

## License Borrowing

License borrowing facilitates users in temporarily "checking out" a floating license directly from the license server. This permits the utilization of the license for a defined period.&#x20;

Once the license is no longer required or when the predetermined time elapses, the user can proceed to "check in" the license.

For more information, see our [**Floating Licenses**](docId:4aUNyPIaL8I2te4NypPx7) documentation.

Floating licenses can be borrowed using two different methods:

1. Defining the hours and days from current time that the user will borrow the license for
2. Defining end date in UTC in format "%Y-%m-%dT%H:%M:%SZ", for example "2022-05-28T15:30:00Z".&#x20;

Below are the programmatic steps required to implement license borrowing using both strategies:

:::CodeblockTabs
```cpp
//1:
license->borrow( hours, days );
//2:
std::string expirydate = "2022-05-28T15:30:00Z"
license->borrow( expirydate );
```

```csharp
//1:
license.Borrow( hours, days );
//2:
var expirydate = "2022-05-28T15:30:00Z"
license.Borrow( expirydate );
```

```swift
try license.borrow(for: 24 * 60 * 60) // 1 day.
```

```python
license.floating_borrow("2031-05-06T00:00:00Z")

```

```go
// Go SDK v2

// Specify the borrow duration in hours and days.
// Alternatively, use a custom timestamp like:
//    t := time.Now().Add(3 * time.Hour).UTC()
//    ld, err = lh.Borrow(ctx, &t)
ld, err = license_handler.BorrowHoursAndDays(ctx, 3, 0)
```

```java
LicenseIdentity identity = LicenseIdentity.fromKey("<LICENSE-KEY>");
ZonedDateTime borrowedUntil = ZonedDateTime.now().plusMinutes(5);

service.borrowLicense(identity, borrowedUntil);
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x57;ith strategy 2 (using an end date in UTC), if the string is left empty, then the license will be borrowed for max possible period.
:::

:::hint{type="danger"}
In C++ and .NET, th&#x65;**&#x20;BorrowLicenseException&#x20;**&#x69;s thrown if borrowing is not allowed or the provided borrowing period is larger than the maximum.
:::

When borrowing a license, it's worth mentioning the divergent behaviors of the license watchdog in different programming contexts.&#x20;

In C++, the license watchdog **ceases operation** upon borrowing, while in .Net, it **temporarily pauses** to avoid interfering with the borrowed license's usage.&#x20;

## Returning the Floating License

Given the finite availability of registration slots, it's crucial to release these spots when not in active use. To facilitate this, the process of deregistering a license becomes vital, enabling other users to register their licenses on their respective devices.

Much like the procedure for registering a floating license, there are several approaches to accomplish license deregistration/release.&#x20;

One option involves manually initiating the deregistration process within your code, allowing you to efficiently free up a registration slot associated with a floating license.

:::CodeblockTabs
```cpp
license->releaseFloatingLicense( false );
```

```csharp
license.Release( false );
```

```swift
try license.releaseFloatingLicense()
```

```python
license.floating_release(False)
```

```go
// Go SDK v2
ld, err = licesen_handler.ReleaseFloatingLicense(ctx)
```

```java
LicenseIdentity identity = LicenseIdentity.fromKey("<LICENSE-KEY>");
service.releaseLicense(identity);
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x54;he Boolean parameter in these manual license release determines whether this method should throw exceptions. By default, it is **false**.&#x20;
:::

Alternatively, you have the option to leverage the auto-release functionality.&#x20;

This feature ensures that whenever your license object undergoes destruction, the associated floating license is automatically released from the device.&#x20;

This proves beneficial because in scenarios such as application closure or crashes, the license object is typically destroyed, facilitating an automatic release of the license.&#x20;

Notably, this feature is already activated by default within the SDK, contributing to streamlined license management.

```cpp
//You can use the parameter to manually turn on/off the auto release feature.
license->setAutoRelease( true ):

if( license->isAutoReleaseSet() )
{
//do something
}
```

:::hint{type="info"}
**Note:&#x20;**&#x54;he parameter in `setAutoRelease()` is used to indicate whether the SDK should automatically release floating license in the destructor.
:::


[title] Java SDK Configuration and Usage
[path] SDKs/Tutorials/Getting Started/Java/

Within this guide, we will meticulously navigate the sequential procedure of enabling your LicenseSpring license by employing the LicenseSpring Java SDK.

As you progress through this tutorial, you will acquire the skills to initiate, deactivate, and verify licenses directly from your Java program.

Functions and methods used throughout this tutorial throw exceptions to understand any potential problems.&#x20;

For more information about these, see [**Java Exception Handling**](docId\:fkkfueJTouLifqaHZxpIg).

## Configuration

To initialize the SDK you will need to fill in your application name and version, LicenseSpring API key, shared key and product code.

Both the API key and shared key can be found on your LicenseSpring account under Settings->Keys:

![API and Shared Key Location](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/GyXxaw6jWl3gCgn-lKMFn_image.png "API and Shared Key Location")

Your product code is located in your product list under "Configure Products":

![Product Code Location](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/6uCNXLQ1QYkYrMk0bXDLd_image.png "Product Code Location")

Please, keep in mind that the product code field is case-sensitive.&#x20;

When you have the necessary values, create the configuration.

```java
LicenseSpringConfiguration configuration = LicenseSpringConfiguration.builder()
                .apiKey("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
                .productCode("javatutorial")
                .sharedKey("XXXXXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXX")
                .appName("NAME")
                .appVersion("VERSION")
                .build();
```

Now you can initialize `LicenseManager` using this configuration object:

```java
LicenseManager licenseManager = LicenseManager.getInstance();

try {
  licenseManager.initialize(configuration);
} catch (LicenseSpringException e) {
  System.out.println(e.getCause().getMessage());
}
```

## License Activation

The license keys are located in "Licenses" section on the vendor platform:

![License Key Location](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/jTyebUmXTL07JEg931EtD_image.png "License Key Location")

To implement user-based licensing please refer to: [**User-Based Licensing**](docId\:xEPx04M3OH_F6s8ylf6mZ).

To activate a license, create a `ActivationLicense` using the given key and call activation method.

```java
ActivationLicense key = ActivationLicense.fromKey("XXXX-XXXX-XXXX-XXXX");
License currentLicense = licenseManager.activateLicense(key);
currentLicense = licenseManager.checkLicense(currentLicense);
```

:::hint{type="info"}
**Note:** We immediately check our license after activating because `activateLicense` only activates the license on the LicenseSpring servers. The license check either creates/updates the local license file, depending on if it existed prior.
:::

## License Deactivation

Deactivating a license unbinds the device from the license, and decrements the number of total activations.&#x20;

Depending on the license transfer policy, this usually means that the license is freed up to be activated onto a new device.&#x20;

Deactivating is done using the following method:

```java
if (licenseManager.deactivateLicense(LicenseIdentity.fromKey("XXXX-XXXX-XXXX-XXXX"))) {
  System.out.println("License deactivated successfully.");
}
```

## Local License

The local license is a copy of the license information that is saved on the end user's local computer. Users who have not activated the license on their end before will not have a local license. By default, the local license is stored: `%USERPROFILE%\AppData\Local\LicenseSpring\”Product Code”\License.key`.

See [**Local License File**](docId\:FkfZHhA-N838tZNrZu0sZ) for more information.

If a device already has a license, and you try to activate another license on that device, for the same product, that newly activated license will override the existing license, deleting it from the device. This will be on the developer to make sure that they check if a license exists on the device before a new activation:

```java
License license = licenseManager.getCurrent();

if (license == null ) {
  //activate a new license
}
```

## License Check

It is recommended to perform a local license check at application start to confirm that the local license file belongs to the current device and has not been transferred.&#x20;

```java
license.localCheck();
```

:::hint{type="info"}
**Note:&#x20;**&#x49;t is also useful to check whether the local license file has been tampered with and whether the local license is still valid.&#x20;
:::

Online license check refreshes the local license with the data from LicenseSpring backend:

```java
license = licenseManager.checkLicense(license);
```

## Full Code Sample

Below you can find a code sample that initializes the SDK, retrieves a local license or activates a new one, and performs the necessary checks.

```java
LicenseSpringConfiguration configuration = LicenseSpringConfiguration.builder()
                .apiKey("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
                .productCode("javatutorial")
                .sharedKey("XXXXXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXX")
                .appName("NAME")
                .appVersion("VERSION")
                .build();
                
LicenseManager licenseManager = LicenseManager.getInstance();

try
  {
    licenseManager.initialize(configuration); 

    License currentLicense = licenseManager.getCurrent();
    
    if (currentLicense == null) {
      ActivationLicense key = ActivationLicense.fromKey("XXXX-XXXX-XXXX-XXXX");
      currentLicense = licenseManager.activateLicense(key);
    }
    
    currentLicense = licenseManager.checkLicense(currentLicense);
    currentLicense.localCheck(); //additional check, not needed of you're doing online check, but good for offline mode
  } catch (LicenseSpringException e) {
    System.out.println(e.getCause().getMessage());
  }
```


[title] Licensing Scenarios
[path] SDKs/Tutorials/

In the dynamic landscape of software distribution and usage, licensing plays a pivotal role in regulating access, protecting intellectual property, and ensuring compliance.&#x20;

Licensing scenarios encompass a diverse range of situations and configurations that software developers and businesses encounter while distributing their products.

This section explores various licensing scenarios that developers, businesses, and end-users may encounter.&#x20;

It examines the different types of software licenses, their purposes, and the implications they have on software usage.&#x20;

From traditional single-user licenses to [**Subscription**](docId\:O79gCxoa72yQlYJl3BbHq) models, [**Floating Licensing**](docId\:yaZxsl7FnxbYi883jYc3-), and [**Offline Licensing**](docId\:Dl6ntbcC17ZFT8grgSERW), each scenario presents unique challenges and advantages.

[title] .NET/C# Management SDK
[path] SDKs/Tutorials/Getting Started/

LicenseSpring Management SDK makes the license management process easy and provides the tools necessary to automate it.

All you need to do is import our SDK into your project, and you're all set to start developing.

If you can't locate the binaries suitable for your particular environment, no need for concern. Just [**submit a support ticket**](https://licensespring.zendesk.com/hc/en-us/requests/new), and we'll gladly compile them for you. Our committed support team is available to guide you through each phase.

Let's get started and unlock the full potential of the extensive capabilities of license management for your .NET/C# application.

[title] License Features
[path] SDKs/Tutorials/Best Practices/

Software vendors frequently need the capability to independently manage entitlements for distinct components or modules within their primary application.

LicenseSpring accomplishes this through its advanced licensing features. It offers two types of feature licensing: consumption-based and activation-based.

This tutorial will explore the effective utilization of license features within your application.

::embed[]{url="https://www.youtube.com/watch?v=2T1yclpXjyA&ab_channel=LicenseSpringSoftware"}

## Prerequisites

1. Completed the Getting Started tutorials, specifically:
   - Initialized LicenseManager (or LicenseHandler) with your configuration using the appropriate settings.
   - Activated a license.

## Types of License Features

- **Activation** features are straightforward, operating as either enabled or disabled based on a license.
- **Consumption** features offer more complexity, featuring a "Maximum Consumptions" parameter that increments the "Total Consumptions" count whenever a user utilizes the feature. Additionally, you have the flexibility to establish overage settings for individual product features and specify a period for resetting consumptions.

## Adding License Features

License features can be added on the LicenseSpring platform, on the product page under "Features".

![Adding Product Feature](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8B209IQ65ygzf6i92J2Uw_image.png "Adding Product Feature")

See our [**Features**](docId\:pTsdhUAr9YJhGPVbKxb4o) page for a more in-depth look at adding license features.

## Accessing License Features

There are two ways of retrieving license features:

- Retrieving a product (license) feature **by feature code**.
- Retrieving **all product features** available for the license.

First, to access a specific license feature within the SDKs, the following method can be used:

:::CodeblockTabs
```cpp
license->feature( "feature_code" );
```

```csharp
license.Feature( "feature_code" );
```

```swift
if let feature = license.features.first(where: { $0.code == "feature_code" }) { ... }

```

```python
response = license.get_feature_data("feature_code") 

print(response)
```

```go
// Go SDK v2
license_data.GetFeature("feature code")
```

```java
License license = this.getCurrent();
LicenseData data = license.getData();
List<LicenseFeature> features = data.getProductFeatures();
```
:::

This method either returns a `LicenseFeature` object with the provided feature code, or throws an `InvalidLicenseFeatureException` if the feature code does not exist.

The other strategies includes receiving all available product features for a given license:

:::CodeblockTabs
```cpp
license->features();
```

```csharp
license.Features();
```

```java
licenseData.getProductFeatures();
```

```swift
let features = license.features
```

```python
features = license.features()

print(features)
```

```go
// Go SDK v2
license_data.FeatureManager.LicenseFeatures
```
:::

The `features()` method returns a vector of `LicenseFeature` objects in the C++ SDK and an array of `LicenseFeature` objects in the .NET SDK.

:::hint{type="info"}
**Note:&#x20;**&#x49;n the Java SDK, `getProductFeatures()` is called on a `LicenseData` object, not `License`.
:::

## Consumption License Features

Consumption feature licensing enables measuring the usage of a feature within the application.&#x20;

This proves valuable when the vendor intends to restrict the frequency of specific functions being executed or reports being generated, among other scenarios.&#x20;

To modify the usage levels of features, the following method is used:

:::CodeblockTabs
```cpp
license->updateFeatureConsumption( "feature_code", 1, true );
```

```csharp
license.UpdateFeatureConsumption( "feature_code", 1 );
```

```java
license.increaseFeatureConsumption( "product_code", 1 );
```

```swift
try license.updateFeatureConsumption(code: "feature_code", difference: 2)
```

```python
license.add_local_feature_consumption("feature_code",1)
```

```go
// Go SDK v2
ld, err = license_handler.UpdateFeatureConsumption(featureCode, 1, true)
```
:::

The first parameter is the unique feature code associated with the feature under update, while the second parameter signifies the consumption value to be added. The last parameter determines whether the update is to be stored locally.

There are two options for measuring consumption on a device: local consumption and total consumption.

When employing local consumption for a specific feature, consumptions are exclusively retrieved from the local license file, bypassing the backend. This approach can be advantageous for caching local consumption amounts per device, as LicenseSpring charges on a per API call basis. Consequently, you can configure the setup such that local consumption synchronization with the backend occurs only when the program concludes or during other designated scenarios.

Total consumption operates differently by encompassing both the total consumption on the LicenseSpring platform and the local consumption on the device. Hence, if total consumption is chosen for a particular feature, all users utilizing the same license will collectively share the consumption pool displayed on the platform.&#x20;

When dealing with total consumption, developers utilize the following to synchronize feature consumption:

:::CodeblockTabs
```cpp
license->syncFeatureConsumption( "feature_code" );
```

```csharp
license.SyncFeatureConsumption( "feature_code" );
```

```java
license.syncConsumptions()
```

```swift
// Sync exact feature:
try license.syncFeatureConsumption(code: "feature_code")

// Sync all features:
try license.syncFeatureConsumption(code: nil)
```

```python
ld, err = license_handler.SyncFeatureConsumption(ctx, featureCode)
```

```go
// Go SDK v2
ld, err = license_handler.SyncFeatureConsumption(ctx, featureCode)
```
:::

It is advisable to call this method before trying to obtain the total consumption value and after updating the total consumption count.&#x20;

If you are syncing properly, then your total consumption should be equal to your local consumption at any time.

:::hint{type="info"}
**Note: To identify expired features**, developers have the option to employ `syncFeatureConsumption`. In cases where a feature has been removed from the license, attempting to locate it using `syncFeatureConsumption` on the LicenseSpring platform will result in an `InvalidLicenseFeatureException` being thrown.
:::

Identifying expired features can also be done through a license check with the `includeExpiredFeatures` parameter. In that case, the API returns a list of all non-expired and expired features:

:::CodeblockTabs
```cpp
bool includeExpiredFeatures = true;
license->check( InstallFileFilter(), includeExpiredFeatures );
```

```python
response = license.check(include_expired_features=True)

print(response)
```
:::


[title] Trial Licensing
[path] SDKs/Tutorials/Licensing Scenarios/

In this guide, we will explore the powerful capabilities of LicenseSpring's trial licensing feature, which enables software vendors to offer time-limited evaluation periods for their products.

## Prerequisites

1. Completed the [**Getting Started**](docId\:LSFY9tQ3vfq4ROOW9sHkd) Tutorial, specifically:
   - Initialized LicenseManager (or LicenseHandler) with your configuration using the appropriate settings.
   - Created a LicenseID using either LicenseID::fromKey or LicenseID::fromUser function, depending on the activation method you prefer.

## Differences Between Trial and Non-Trial Licenses

Distinguishing trial and non-trial licenses involves several key differences:

1. **Limited Validity:** Trial licenses have a predefined expiration date, restricting the user's access to the software after this date. In contrast, non-trial licenses typically have no time restrictions, allowing perpetual usage.
2. **Identifiability:** The LicenseSpring SDKs can recognize trial licenses as distinct entities. This enables developers to implement conditional logic based on the license type. For instance, specific features can be locked off for trial licenses, providing a tailored trial experience.

## Allowing multiple licenses on trial

Inside Settings --> Preferences --> Allow multiple licenses on trial. This checkbox will allow you to create unlimited trial on same hardware\_id.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/DeO_ShGLGD1p6H6yyIFgO_image.png)

## Getting a Trial License Using the SDK

By integrating a LicenseSpring SDK into your application's codebase, you gain the ability to effortlessly generate and activate trial licenses.&#x20;

It is shown how to create and enable a key-based trial license below:

:::CodeblockTabs
```cpp
LicenseID LicenseSpring::LicenseManager::getTrialLicense( Customer::ptr_t 	user = nullptr, const std::string &licensePolicy = std::string() )	
```

```csharp
LicenseID LicenseSpring.LicenseManager.GetTrialLicense(	Customer user = null, string licensePolicy = null )	
```

```java
UnactivatedTrialLicense getTrialLicense( com.licensespring.model.Customer customer )
```

```swift
let customer = Customer(...)
let key = try manager.requestTrialKey(with: customer)
```

```python
customer = Customer(email='python_policy@gmail.com')  

manager = LicenseManager(conf)

license_id = manager.get_trial_license(customer=customer,license_policy='test')
    
license = manager.activate_license(license_id=license_id)
```

```go
// Go SDK v2
	customer := types.Customer{
		Email:     "fa.bagheri.a@gmail.com",
		FirstName: "fatemeh",
		City:      "vancouver",
	}

	ld, err := license_handler.GetTrialKey(customer, "")
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x57;hen using a key-based trial license, we leave the first parameter as a nullptr. When issuing a user-based trial license, we input the user email.
:::

:::hint{type="info"}
**Note:&#x20;**&#x49;f we leave the second parameter, or pass it an empty string, it will use our default license policy to create our trial license. Otherwise, we can pass it a specific license policy code to use that policy's license settings.
:::

It is also possible to pass a string of an email as the lone parameter, as shown below:

:::CodeblockTabs
```cpp
LicenseID LicenseSpring::LicenseManager::getTrialLicense( const std::string &userEmail)	
```

```csharp
LicenseID LicenseSpring.LicenseManager.GetTrialLicense( string 	email )	
```

```java
UnactivatedTrialLicense getTrialLicense( String email )
```

```swift
let key = try manager.requestTrialKey(with: "testcustomer@foo.com")
```
:::

## Determining if the Current License Is a Trial

It is straightforward to check whether the current license in your software application is a trial license.

Each SDK has a method within the `License` object that allows developers to distinguish between trial and non-trial licenses, as shown below:

:::CodeblockTabs
```cpp
if ( license->isTrial() )
  {
    //Trial license code
  }
else
  {
    //Normal license code
  }
```

```csharp
if ( license.IsTrial() )
  {
    //Trial license code
  }
else
  {
    //Normal license code
  }
```

```java
if ( license.getData().isTrial() )
  {
    //Trial license code
  }
else
  {
    //Normal license code
  }
```

```swift
license.isTrial
```

```python
 if license.is_trial():
     pass #if license is trial
 else:
     pass #license not trial
```
:::

## Sample Code for Obtaining and Activating a Trial License

The following sample code illustrates obtaining and activating trial licenses for both key and user-based licenses.

For the sample code to operate for user-based license, simply replace the nullptr in `Customer::ptr_t user = nullptr` with a `Customer` object.

Also, `licensePolicyCode` can be set to the string of any license policy code associated with the license, otherwise if left as empty it will use the default license policy.

:::CodeblockTabs
```cpp
Customer::ptr_t user = nullptr;
const std::string licensePolicyCode = std::string();
LicenseID licenseId;
    
try
  {
    licenseId = licenseManager->getTrialLicense( user, license_policy_code );
    //licenseId = licenseManager->getTrialLicense( user->email );
  }
catch ( TrialNotAllowedException )
  {
    //Trial is not allowed on current product + license_policy combination
  }
catch ( ProductNotFoundException )
  {
    //Product could not be found on server. Please make sure your API key, Shared key, and Product Code are all correct.
  }
catch ( MissingEmailException )
  {
    //User based products require an email, even for trial licenses.
  }
catch ( ... )
  {
    //Possible network issue.
  }
```

```python
manager= LicenseManager(conf)

customer = Customer(email='python_policy@gmail.com')  

manager = LicenseManager(conf)

license_id = manager.get_trial_license(customer=customer,license_policy='test')

try:
    license = manager.activate_license(license_id=license_id)

except Exception as ex:
    print(ex)
```

```java
UnactivatedTrialLicense trial = licenseManager.getTrialLicense("python_policy@gmail.com");
License license = licenseManager.activateLicense(trial.createIdentity());
```
:::

After activating a trial license, developers can control the state of the application through the `isTrial()` method accessible through the `License` object.

This functionality is shown below:

:::CodeblockTabs
```cpp
//Creating/updating trial license.
license = licenseManager->activateLicense( licenseId );

if ( license->isTrial() )
  {
    //Currently using a trial license.
    //Showing limited options.
  }
else
  {
    //Currently using a non-trial license.
    //Showing full account options.
  }
```

```python
manager= LicenseManager(conf)

customer = Customer(email='python_policy@gmail.com')  

manager = LicenseManager(conf)

license_id = manager.get_trial_license(customer=customer,license_policy='test')
    
license = manager.activate_license(license_id=license_id)
        
if license.is_trial():
    pass #limited options

else:
    pass #full set of features
```

```java
UnactivatedTrialLicense trial = licenseManager.getTrialLicense("python_policy@gmail.com");
License license = licenseManager.activateLicense(trial.createIdentity());
LicenseData data = license.getData();

if (data.isTrial()) {
  // limited options
} else {
  // full set of features
}
```
:::

## Troubleshooting

### Exceptions Related to Trial Licensing

Exceptions that might occur when performing offline license activation:

- **TrialNotAllowedException:&#x20;**&#x54;rial is not allowed by product license policy.


[title] API Client Usage Examples
[path] SDKs/Python SDK/

### Set app version

```python
import licensespring

licensespring.app_version = "MyApp 1.0.0"
```

### Create APIClient

An **API client** can use either **API keys&#x20;**(`shared_key` and `api_key`) or **OAuth&#x20;**(`client_id` and `client_secret`) for **authorization**.

```python
from licensespring.api import APIClient

api_client = APIClient(api_key="_your_api_key_", shared_key="_your_shared_key_")
```

```python
from licensespring.api import APIClient

api_client = APIClient(client="_your_client_id_", client_secret="_your_client_secret_")
```

### Activate key based license

```python
product = "lkprod1"
license_key = "GPB7-279T-6MNK-CQLK"
license_data = api_client.activate_license(product=product, license_key=license_key)

print(license_data)
```

### Activate user based license

```python
product = "uprod1"
username = "user1@email.com"
password = "nq64k1!@"

license_data = api_client.activate_license(
    product=product, username=username, password=password
)

print(license_data)
```

### Deactivate key based license

```python
product = "lkprod1"
license_key = "GPUB-J4PH-CGNK-C7LK"
api_client.deactivate_license(product=product, license_key=license_key)
```

### Deactivate user based license

```python
product = "uprod1"
username = "user1@email.com"
password = "nq64k1!@"

api_client.deactivate_license(
    product=product, username=username, password=password
)
```

### Activate key based bundle

```python
product = "lkprod1"
license_key = "GPB7-279T-6MNK-CQLK"
license_data = api_client.activate_bundle(product=product, license_key=license_key)
```

### Activate user based bundle

```python
product = "uprod1"
username = "user1@email.com"
password = "nq64k1!@"

license_data = api_client.activate_bundle(
    product=product, username=username, password=password
)

print(license_data)
```

### Deactivate key based bundle

```python
product = "lkprod1"
license_key = "GPB7-279T-6MNK-CQLK"
license_data = api_client.deactivate_bundle(product=product, license_key=license_key)
```

### Deactivate user based bundle

```python
product = "uprod1"
username = "user1@email.com"
password = "nq64k1!@"
license_data = api_client.deactivate_bundle(product=product, username=username, password=password)

print(license_data)
```

### Check key based bundle

```python
product = "lkprod1"
license_key = "GPB7-279T-6MNK-CQLK"
license_data = api_client.check_bundle(product=product, license_key=license_key)
```

### Check user based bundle

```python
product = "uprod1"
username = "user1@email.com"
password = "nq64k1!@"
license_data = api_client.check_bundle(product=product, username=username, password=password)

print(license_data)
```

### Check key based license

```python
product = "lkprod1"
license_key = "GPBQ-DZCP-E9SK-CQLK"

license_data = api_client.check_license(product=product, license_key=license_key)

print(license_data)
```

### Check user based license

```python
product = "uprod1"
username = "user2@email.com"
password = "1l48y#!b"

license_data = api_client.check_license(product=product, username=username)

print(license_data)
```

### Add consumption

```python
product = "lkprod1"
license_key = "GPSU-QTKQ-HSSK-C9LK"

# Add 1 consumption
consumption_data = api_client.add_consumption(
    product=product, license_key=license_key
)

print(consumption_data)

# Add 3 consumptions
consumption_data = api_client.add_consumption(
    product=product, license_key=license_key, consumptions=3
)

print(consumption_data)

# Add 1 consumption, allow overages and define max overages
consumption_data = api_client.add_consumption(
    product=product, license_key=license_key, allow_overages=True, max_overages=10
)

print(consumption_data)
```

### Add feature consumption

```python
product = "lkprod1"
license_key = "GPTJ-LSYZ-USEK-C8LK"
feature = "lkprod1cf1"

# Add 1 consumption
feature_consumption_data = api_client.add_feature_consumption(
    product=product, license_key=license_key, feature=feature
)

# Add 3 consumptions
feature_consumption_data = api_client.add_feature_consumption(
    product=product, license_key=license_key, feature=feature, consumptions=3
)

print(feature_consumption_data)
```

### Trial key

```python
product = "lkprod2"

trial_license_data = api_client.trial_key(product=product)

print(trial_license_data)
```

### Product details

```python
product = "lkprod1"

product_data = api_client.product_details(product=product)

print(product_data)
```

### Track device variables

```python
product = "lkprod1"
license_key = "GPUB-SZF9-AB2K-C7LK"
variables = {"variable_1_key": "variable_1_value", "variable_2_key": "variable_2_value"}

device_variables = api_client.track_device_variables(product=product, license_key=license_key, variables=variables)

print(device_variables)
```

### Get device variables

```python
product = "lkprod1"
license_key = "GPUB-SZF9-AB2K-C7LK"

device_variables = api_client.get_device_variables(product=product, license_key=license_key)

print(device_variables)
```

### Floating borrow

```python
product = "lkprod1"
license_key = "GPUC-NGWU-3NJK-C7LK"

# Borrow for 2 hours
borrowed_until = (datetime.utcnow() + timedelta(hours=2)).isoformat()
floating_borrow_data = api_client.floating_borrow(product=product, license_key=license_key, borrowed_until=borrowed_until)

print(floating_borrow_data)
```

### Floating release

```python
product = "lkprod1"
license_key = "GPUC-NGWU-3NJK-C7LK"

api_client.floating_release(product=product, license_key=license_key)
```

### Change password

```python
username = "user4@email.com"
password = "_old_password_"
new_password = "_new_password_"

is_password_changed = api_client.change_password(username=username, password=password, new_password=new_password)

print(is_password_changed)
```

### Versions

```python
product = "lkprod1"
license_key = "GPB7-279T-6MNK-CQLK"

# Get versions for all environments
versions_data = api_client.versions(product=product, license_key=license_key)

# Get versions for mac environment
mac_versions_data = api_client.versions(
    product=product, license_key=license_key, env="mac"
)

print(versions_data)
```

### Installation file

```python
product = "lkprod1"
license_key = "GPB7-279T-6MNK-CQLK"

# Get the latest installation file
installation_file_data = api_client.installation_file(
    product=product, license_key=license_key
)

# Get the latest installation file for linux environment
installation_file_data = api_client.installation_file(
    product=product, license_key=license_key, env="linux"
)

# Get the latest installation file for version 1.0.0
installation_file_data = api_client.installation_file(
    product=product, license_key=license_key, version="1.0.0"
)

print(installation_file_data)
```

### Customer license users

```python
product = "uprod1"
customer = 'c1@c.com'

customer_license_users_data = api_client.customer_license_users(
    product=product, customer=customer
)

print(customer_license_users_data)
```

### SSO URL

```python
product = "uprod1"
customer_account_code = "ccorp"

sso_url_data = api_client.sso_url(
    product=product, customer_account_code=customer_account_code
)

print(sso_url_data)
```

### SSO URL with `code` response type

```python
product = "uprod1"
customer_account_code = "ccorp"

sso_url_data = api_client.sso_url(
    product=product,
    customer_account_code=customer_account_code,
    response_type="code",
)

print(sso_url_data)
```

### Activate offline

```python
product = "lkprod1"
license_key = "GPY7-VHX9-MDSK-C3LK"

# Generate data for offline activation
activate_offline_data = api_client.activate_offline_dump(
    product=product, license_key=license_key
)

# Write to file
with open('activate_offline.req', mode='w') as f:
    print(activate_offline_data, file=f)

# Activate offline
license_data = api_client.activate_offline(data=activate_offline_data)

print(license_data)
```

### Activate offline load

```python
# Read from file
with open('./ls_activation.lic') as file:
    ls_activation_data = file.read()

license_data = api_client.activate_offline_load(ls_activation_data)

print(license_data)
```

### Deactivate offline

```python
product = "lkprod1"
license_key = "GPYC-X5J2-L5SK-C3LK"

# Generate data for offline deactivation
deactivate_offline_data = api_client.deactivate_offline_dump(
    product=product, license_key=license_key
)

# Write to file
with open('deactivate_offline.req', mode='w') as f:
    print(deactivate_offline_data, file=f)

# Deactivate offline
api_client.deactivate_offline(data=deactivate_offline_data)
```

### Key based license feature check

```python
product = "lkprod1"
license_key = "GPB7-279T-6MNK-CQLK"
feature = "lkprod1f1"

license_feature_data = api_client.check_license_feature(
    product=product, feature=feature, license_key=license_key
)

print(license_feature_data)
```

### Key based license floating feature release

```python
product = "lkprod1"
license_key = "GPB7-279T-6MNK-CQLK"
feature = "lkprod1f1"

api_client.floating_feature_release(
    product=product, feature=feature, license_key=license_key
)
```

```python
product = "lkprod1"
license_key = "GPB7-279T-6MNK-CQLK"
feature = "lkprod1f1"

is_released = api_client.floating_feature_release(
    product=product, feature=feature, license_key=license_key
)

print(is_released)
```


[title] .NET SDK Configuration and Usage
[path] SDKs/Tutorials/Getting Started/.NET/C#/

This guide will walk you through the step-by-step process of configuring your LicenseSpring license using the LicenseSpring .NET SDK.

As you advance through this tutorial, you'll gain the expertise to activate, deactivate, and verify licenses directly from your .NET application.

Throughout this tutorial, functions and methods employed may throw exceptions to address potential issues.

For more information about these, see [**Error Handling**](docId:_0Tnmm6ShDrCmLpx4TuOO).

## Configuration

To initialize the SDK, you must fill in your application name and version, LicenseSpring API key, shared key and product code.

Both the API key and shared key can be found on your LicenseSpring account under Settings->Keys:

![API and Shared Key Location](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/qp4PTqnTV2l2iS1sTmKn5_image.png "API and Shared Key Location")

Your product code is located in your product list under "Configure Products":

![Product Code Location](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/M4Ii6KreWKfvVkT9ACmr3_image.png)

Please, keep in mind that the product code field is case-sensitive.&#x20;

When you have the necessary values, create the configuration as shown below:

```csharp
var configuration = new LicenseSpring.Configuration(
  apiKey: "API KEY",
  sharedKey: "SHARED KEY",
  productCode: "PRODUCT SHORT CODE",
  appName: "APP NAME",
  appVersion: "VERSION");
// Or use OAuth instead of API keys:
OAuthCredentials oAuth = new OAuthCredentials("CLIENT ID", "CLIENT SECRET");
// Don't forget to provide your CryptoProvider key if you will use the default crypto provider. If you will provide your own ICryptoProvider implementation you can skip this.
oAuth.CryptoProviderKey = "My secret crypto key.";
configuration = new LicenseSpring.Configuration(
  oAuthCredentials: oAuth,
  productCode: "PRODUCT SHORT CODE",
  appName: "APP NAME",
  appVersion: "VERSION");
```



Now you can initialize `LicenseManager` using this configuration object:

```csharp
var licenseManager = LicenseManager.GetInstance();
licenseManager.Initialize(configuration); 
```

## License Activation

The license keys are located in "Licenses" section on the vendor platform:

![License Key Location](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/tkZUO-Ut3up1SXzxNIj9R_image.png "License Key Location")

To implement user-based licensing please refer to: [**User-Based Licensing**](docId\:xEPx04M3OH_F6s8ylf6mZ).

To activate a license, create a `LicenseID` using the given key and call activation method.

```csharp
try 
{
  LicenseID licenseId = LicenseID.FromKey( licenseKey );
  var license = licenseManager.ActivateLicense( licenseId );
} 
catch( LicenseActivationException e )
{
  //...
}
```

:::hint{type="info"}
**Note:&#x20;**`ActivateLicense` returns the activated `License` object if the activation is successful.
:::

:::hint{type="danger"}
`ActivateLicense` can throw many different exceptions, for information on why they're thrown and how to handle them, see [**Error Handling**](docId:_0Tnmm6ShDrCmLpx4TuOO).
:::

:::hint{type="info"}
**InvalidOperationException&#x20;**&#x63;an occur due to incorrect use of the `ActivateLicense `function. This function has two overloads. For a regular license activation, it takes only `LicenseID`. The overload that takes strings is used for SSO. For more information, see [**Single Sign-On**](docId\:FWGT-4DZ4zIEWEl1Nosxq).
:::

## License Deactivation

Deactivating a license unbinds the device from the license, and decrements the number of total activations.&#x20;

Depending on the license transfer policy, this usually means that the license is freed up to be activated onto a new device.&#x20;

Deactivating is done using the following method:

```csharp
var isDeactivated = license.Deactivate();
```

:::hint{type="info"}
**Note:&#x20;**`Deactivate()`has an optional Boolean parameter that can be passed to determine whether the local license and folders created by the SDK should also be removed. This parameter is **false by default**.
:::

:::hint{type="info"}
**Note:&#x20;**`Deactivate()`returns true if successfully deactivated and false otherwise. It also returns true if the license is already inactive.
:::

## Local License

The local license is a copy of the license information that is saved on the end user's local computer. Users who have not activated the license on their end before will not have a local license. By default, the local license is stored: `%USERPROFILE%\AppData\Local\LicenseSpring\”Product Code”\License.key`.

See [**Local License File**](docId\:FkfZHhA-N838tZNrZu0sZ) for more information.

If a device already has a license, and you try to activate another license on that device, for the same product, that newly activated license will override the existing license, deleting it from the device. This will be on the developer to make sure that they check if a license exists on the device before a new activation.

The current license can be retrieved with:

```csharp
var currentLicense = licenseManager.CurrentLicense();
```

:::hint{type="info"}
**Note:** If no active license is available, `currentLicense` will be set to `null`.
:::

## License Check

It is recommended to perform a local license check at application start to confirm that the local license file belongs to the current device and has not been transferred.&#x20;

A local license check is performed in the .NET SDK with:

```csharp
license.LocalCheck();
```

:::hint{type="info"}
**Note:&#x20;**&#x49;t is also useful to check whether the local license file has been tampered with and whether the local license is still valid.&#x20;
:::

Online license check refreshes the local license with the data from LicenseSpring backend are done with:

```javascript
var installationFile = license.Check();
```

This method also returns the most recent `InstallationFile` available for the license which can be useful for managing software updates.

For more information about managing software updates, see [**Handling Product Versions**](docId\:ZvfCf4-5cQ4UJ4dnsOvBb).

You can also check for active, valid, enabled, and expired licenses using `isActive`, `isValid`, `isEnabled`, and `isExpired` methods respectively.&#x20;

Note that an active license does not necessarily mean a license is valid. A valid license means the license is active, enabled, and not expired. An active license means that the license is bound to a device, but may also be disabled or expired.

## Full Code Sample

Below you can find a code sample that initializes the SDK, retrieves a local license or activates a new one, and performs the necessary checks.

```csharp
var configuration = new LicenseSpring.Configuration(
  apiKey: "API KEY",
  sharedKey: "SHARED KEY",
  productCode: "PRODUCT SHORT CODE",
  appName: "APP NAME",
  appVersion: "VERSION");
  
try
{
  var licenseManager = LicenseManager.GetInstance();
  licenseManager.Initialize(configuration); 
  var currentLicense = licenseManager.CurrentLicense();
  if( currentLicense == null )
  {
     LicenseID licenseId = LicenseID.FromKey( licenseKey );
     currentLicense = licenseManager.ActivateLicense( licenseId );
  }
  currentLicense.LocalCheck();
  currentLicense.Check();
}
catch (const LicenseSpringException& ex )
{
  Console.WriteLine("Exception encountered");
}
```


[title] Swift SDK Configuration and Usage
[path] SDKs/Tutorials/Getting Started/Swift / Objective-C/

Swift SDK allows implementing licensing using the **License&#x20;**&#x61;nd **LicenseManager&#x20;**&#x63;lasses.

This article has code samples for both approaches. In the other ones, we will demonstrate  SDK usage only with **LicenseManager&#x20;**&#x61;nd **License**. **LicenseHandler&#x20;**&#x63;lass has methods corresponding to **License**/**LicenseManager&#x20;**&#x66;unctionality.&#x20;

## Configuration

To initialize the SDK, you must fill in your application name and version, LicenseSpring API key, shared key and product code.

Both the API key and shared key can be found on your LicenseSpring account under Settings->Keys:

![API and Shared Key Location](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/E8UhHrENKuF-RQw50B4nn_screenshotkeys.png "API and Shared Key Location")

Your product code is located in your product list under Configure Products:

![Product CoProduct Code Location Location](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/LGlB_ERjJM0YF_0EHtMt2_screenshotproduct.png "Product Code Location")

Please, keep in mind that the product code field is case-sensitive.&#x20;

When you have the necessary values, create the **Configuration**.

```swift
let configuration = Configuration(
    apiKey: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    sharedKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    productCode: "XX"
)
configuration.appName = "My LicenseSpring Application"
configuration.appVersion = "1.0.0"
```

Configuration has been extended with nullable extendedOptions parameter, which at this time can be used for as guarding your offline activations. Example of configuration object with this parameter can be seen below.

```swift
let configuration = Configuration(
    apiKey: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    sharedKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    productCode: "XX",
    extendedOptions: ExtendedOptions(protectOfflineActivation: true)
)
configuration.appName = "My LicenseSpring Application"
configuration.appVersion = "1.0.0"
```

Now you can initialize **LicenseManager** using this configuration object.
*If apiKey sharedKey or productCode is empty, the error is thrown.*

:::CodeblockTabs
LicenseManager

```swift
let manager = try LicenseManager(configuration: configuration)
```
:::

## License Activation

The license keys are located in Licenses section:

![License Key Location](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/xUdyMD7vPArcHnhvLlQxY_screenshotlicense.png "License Key Location")

To implement user-based licensing please refer to: [**User-Based Licensing**](docId\:xEPx04M3OH_F6s8ylf6mZ).

To activate a license, create a **LicenseID** using the given key and call activation method.

:::CodeblockTabs
LicenseManager

```swift
 let license = try manager.activateLicense(licenseKey: "XXXX-XXXX-XXXX-XXXX")
```
:::

The process of activating a license refers to binding a device to a license. On the LicenseSpring platform, activating the license increments the total activations counter within the license.

## Local License

The local license is a copy of the license information that is saved on the end user's local computer. Users who have not activated the license on their end before will not have a local license. By default, the local license is stored: `~/Library/Application Support/<Process Name>/<Product Code>/license.ls`.

*License key path and license key name may be customized through Configuration*

See [**Local License File**](docId\:FkfZHhA-N838tZNrZu0sZ) for more information.

If a device already has a license, and you try to activate another license on that device, for the same product, that newly activated license will override the existing license, deleting it from the device. This will be on the developer to make sure that they check if a license exists on the device before a new activation:

:::CodeblockTabs
LicenseManager

```swift
if let license = manager.currentLicense { ... }
```
:::

## License Check

It is recommended to perform a local license check at application start to confirm that the local license file belongs to the current device and has not been transferred.&#x20;

It is also useful to check whether the local license file has been tampered with and whether the local license is still valid.&#x20;

:::CodeblockTabs
License

```swift
try license.localCheck()
//throws in case of errors
```
:::

Full check (online check) license check performs synchronization of local license with the data from LicenseSpring backend:

:::CodeblockTabs
License

```swift
try license.fullCheck()
//throws in case of errors
```
:::

This methods also updates information of InstallationFile.
For more information about managing software updates, see [**Handling Product Versions**](docId\:ZvfCf4-5cQ4UJ4dnsOvBb).

You can also check for active, valid, enabled, and expired licenses using `isActive`, `isValid`, `isEnabled`, and `isExpired` methods respectively.&#x20;

Note that an active license does not necessarily mean a license is valid. A valid license means the license is active, enabled, and not expired. An active license means that the license is bound to a device, but may also be disabled or expired.

## Full Code Sample

Below you can find a code sample that initializes the SDK, retrieves a local license or activates a new one, and performs the necessary checks.

:::CodeblockTabs
LicenseManager

```swift
do {
    let configuration = Configuration(
        apiKey: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        sharedKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        productCode: "XX"
    )
    configuration.appName = "My LicenseSpring Application"
    configuration.appVersion = "1.0.0"
    
    let manager = try LicenseManager(configuration: configuration)
    let license = try manager.activateLicense(licenseKey: "XXXX-XXXX-XXXX-XXXX")
    try license.localCheck()
    try license.fullCheck()
} catch {
    print("Error occured: \(error)")
}
```
:::

## License Deactivation

Deactivating a license unbinds the device from the license, and decrements the number of total activations. Depending on the license transfer policy, this usually means that the license is freed up to be activated onto a new device. Deactivating is done using the following method:

:::CodeblockTabs
License

```swift
try license.deactivate()
```
:::

To remove local license file after the deactivation use `LicenseManager.clearLocalStorage` method.

[title] Hardware Key Usage
[path] SDKs/Tutorials/Advanced Usage/

LicenseSpring allows users to bind licenses to a YubiKey hardware key dongle.&#x20;

## Prerequisites

Make sure to set up a YubiKey on the LicenseSpring platform and the LicenseSpring Provisioning Application for Desktop. See [**Hardware Key Licensing**](docId\:tWAsrTiNMFw7Pb0qEWr6a) for instructions.

### C++ Platform-specific Library Placement

Since **C++ SDK v7.37.0**, we provide both LicenseSpring SDK libs that do link, and that don't link to [**libykpiv**](https://developers.yubico.com/yubico-piv-tool/). All samples also have multiple configurations, with and without linking to `libykpiv`.

- **Linux & macOS**
  - Shared libraries are located in `bin/shared_HardwareKey`
  - Static libraries are located in `bin/static_HardwareKey`
  - Note: The existing `bin/shared` and `bin/static` folders remain unchanged and do not link to `libykpiv`.
- **Linux ARM (i.e. ARM without hf support), ppc64le**
  - SDK builds targeting arm and ppc64le architectures do not link tl `libykpiv` (no hardware key support).
- **MSVC (Windows)**
  - Dynamic libraries are located in `bin/dynamic_HardwareKey`
  - Static linking to `libykpiv` is **not supported**.
  - The existing `bin/dynamic` folder remains unchanged and does not link to `libykpiv`.
- **MinGW**
  - We currently don't support hardware&#x20;

The `libykpiv` library has an external dependency which should be installed on user machines:

&#x9;•	Linux uses the pcsc backend (via pcsclite) to manage the YubiKey,
&#x9;•	macOS uses the macscard backend (Apple’s built‑in PC/SC layer, pcsclite daemon),
&#x9;•	Windows (MSVC targets) uses the winscard backend (Microsoft’s WinSCard API).

### Usage samples

:::CodeblockTabs
```cpp
#include <LicenseSpring/Configuration.h>
#include <LicenseSpring/ExtendedOptions.h>

// ...

// the following function returns an std::vector of all plugged YubiKeys' serials.
auto serials = LicenseSpring::HardwareKeyOptions::ListAvailableKeys();
if (!serials.empty()) {
    HardwareKeyOptions hwKeyOptions;
    hwKeyOptions.setTargetSerial(serials[0]); // query the user for the correct serial
    hwKeyOptions.setPin("123456"); // query the user for the pin

    ExtendedOptions options;
    options.setHardwareKeyOptions(hwKeyOptions);
}
```

Java

```java
IdentityProvider identityProvider = config.getIdentityProvider();
String key = identityProvider.getKey();

```

C#

```csharp
// the following function returns a list of all plugged YubiKeys' serials.
List<string> serials = LicenseSpring.HardwareKeyOptions.ListAvailableKeys();
if (serials.Count != 0)
{
    // query the user for the correct serial
    string serialNumber = serials.First();
    // query the user for the correct pin
    string pin = "123456"; 
    
    LicenseSpring.HardwareKeyOptions hardwareKeyOptions = new LicenseSpring.HardwareKeyOptions(serialNumber, pin);
    LicenseSpring.Configuration configuration = new LicenseSpring.Configuration();
}
```
:::

Calling `ExtendedOptions::setHardwareKeyOptions` automatically sets the machine hardware ID to the serial of the Yubikey.

Afterwards, all calls to the License API require that YubiKey to be plugged in, and `License::localCheck` will throw an appropriate `LicenseSpring::HardwareKeyException` exception in case the YubiKey is not plugged in.

[title] C++
[path] SDKs/Tutorials/Getting Started/

Integrating software licensing into your C/C++ application is straightforward with the LicenseSpring SDK.&#x20;

Simply import our SDK into your project, and you're ready to go.&#x20;

If you don't find the binaries for your specific environment, contact our sales department.

[title] Best Practices
[path] SDKs/Tutorials/

In this section, we explore a comprehensive set of best practices tailored specifically for LicenseSpring SDKs.&#x20;

By following these guidelines, you'll not only harness the full potential of our SDKs but also ensure the seamless integration of robust licensing mechanisms into your applications.&#x20;

From [**Offline Licensing**](docId\:Dl6ntbcC17ZFT8grgSERW) to [**Floating Server Usage**](docId:0q73UcB2eH6DGGBJl-3EI), this section is your guide to implementing licensing implementation specifics within the LicenseSpring SDKs.

[title] Swift/Objective-C
[path] SDKs/Tutorials/Getting Started/

Integrating software licensing into your macOS / iOS application is straightforward with the LicenseSpring SDK.&#x20;

Simply import our LicenseSpring.xcframework into your project, and you're ready to go.&#x20;

If you don't find the binaries for your specific environment, or if you want to use the SDK for tvOS / watchOS, just [**submit a support ticket**](https://licensespring.zendesk.com/hc/en-us/requests/new), and we'll be happy to compile them for you. Our dedicated support team is here to assist you every step of the way.&#x20;

Let's get started and unlock the full potential of licensing and entitlement management in your application.

[title] Extended Configuration
[path] SDKs/Tutorials/Advanced Usage/

LicenseSpring offers many features to tailor the setup to meet user needs through the `Configuration` and `ExtendedOptions` classes. Throughout this tutorial, we'll provide a comprehensive overview of these classes and how they are used to manage settings.

In addition to the theoretical understanding, this tutorial also offers practical guidance. You'll find instructions on how to set up a proxy, a crucial element in various software setups. We'll also cover the important topic of SSL checks, discussing their importance and how to integrate them effectively.

This tutorial will provide readers with a solid understanding of the `Configuration` and `ExtendedOptions` classes, acquired practical skills in configuring proxies, and obtained insights into enhancing security through SSL checks.

**Swift** SDK does not have separated `ExtendedConfiguration`: all properties are defined in the `Configuration`itself.

## Accessing Current Configuration

The current configuration can be retrieved by calling `currentConfig()` on a `LicenseManager` instance in the C++ SDK:

:::CodeblockTabs
```cpp
configuration = licenseManager->currentConfig();
```

```python
manager = LicenseManager(conf)

config = manager.current_config()

print(config)
```

Java

```java
LicenseSpringConfiguration config = licenseManager.getConfig();
```
:::

It is also possible to reconfigure the current configuration, rather than having to create a new `Configuration` object with:

:::CodeblockTabs
```cpp
reconfigure( configuration );
```

```python
manager = LicenseManager(conf)

manager.reconfigure(
        Configuration(
            product="lkprod2",
            api_key="new_key",
            shared_key="new_key",
            file_key="file_key",
            file_iv="file_iv",
            file_path="bb",
            grace_period_conf=12,
            is_guard_file_enabled=True,
        )
    )
```

Java

```java
licenseManager.reinitialize(configuration);
```

```swift
try licenseManager.reconfigure(
            appName: "AA[[",
            appVersion: "2.0.1",
            airgapKey: "someAirgapKey",
            skipResponseSignatureChecks: true)
```
:::

:::hint{type="danger"}
**Warning:&#x20;**`reconfigure()` is not thread safe.
:::

## Network Information and Timeout

To activate the gathering of network information, you need to declare it during the configuration phase of the implementation, as follows:

:::CodeblockTabs
```cpp
extendedOptions.collectNetworkInfo( true );
```

```csharp
extendedOptions.CollectNetworkInfo = true;
//OR
configuration.CollectNetworkInfo = true;
```

```swift
configuration.collectHostNameAndLocalIP = true
```

Java

```java
configuration.storeMachineInfo = true;
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x4E;etwork data collection is deactivated by default when left unset.
:::

Whether network collection is enabled can be checked after configuration with:

:::CodeblockTabs
```cpp
bool enabled = extendedOptions.isCollectNetworkInfoEnabled();
//OR
bool enabled = configuration->isCollectNetworkInfoEnabled();
```

```csharp
bool enabled = extendedOptions.CollectNetworkInfo;
//OR
bool enabled = configuration.CollectNetworkInfo;
```

```swift
configuration.collectHostNameAndLocalIP
```

Java

```java
boolean enabled = baseConfiguration.isStoreMachineInfo();
```
:::

A variety of network-related information can be accessed through both `ExtendedOptions` and `Configuration` in C++ and `Configuration` in .NET.

In C++, a `NetworkInfo` object is returned when `getNetworkInfo` is called. The `NetworkInfo` object consists of the following:

- IP address
- MAC address
- Host name

In .NET, the IP address, MAC address, and host name are stored separately in `Configuration`.

In the Python SDK, network information is managed within the [**Python Hardware (Device) IDs**](docId\:ORDujMleQE_0SSSxxa3bQ)  class, which is designed to be customizable. If a user prefers not to send network information, they can override the relevant method in the class to return `None`. This information can be accessed using the following:

:::CodeblockTabs
```cpp
//Through ExtendedOptions
const NetworkInfo& networkInfo = extendedOptions.getNetworkInfo();
//Through Configuration
const NetworkInfo& networkInfo = configuration->getNetworkInfo();

string IPAddress = networkInfo.ip();
string MACAddress = networkInfo.mac();
string hostname = networkInfo.hostName();
```

```csharp
string hostname = configuration.Hostname;
string ip = configuration.LocalIp;
string MACAddress = configuration.MACAddress;
```

```python
# This will overwrite HardwareIdProvided and disable sending network data and OS data.
# This approach allows you to disable fields which fit user needs or set them to some default value.

class CustomHardwareIdProvider(HardwareIdProvider):

    def get_os_ver(self):
        return None

    def get_hostname(self):
        return None

    def get_ip(self):
        return None

    def get_is_vm(self):
        return False

    def get_vm_info(self):
        return None

    def get_mac_address(self):
        return None

```

Java

```java
MachineInfo machineInfo = HardwareInfo.getMachineInfo();
String macAddress = machineInfo.getMacAddress();
String ipAddresses = machineInfo.getIpAddresses();
String hostname = machineInfo.getHostname();
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x54;he above code snippet assumes that a `Configuration` object named "configuration" and `ExtendedOptions` object named "extendedOptions" already exist.
:::

### Override Network Information

C++ offers a method for overriding network information, setting the `NetworkInfo` object stored within `ExtendedOptions`:

```cpp
extendedOptions.overrideNetworkInfo( networkInfo );
```

### Network Timeout

Similarly, the network timeout of the configuration is stored in the same locations, and can be accessed with:

:::CodeblockTabs
```cpp
long timeout = extendedOptions.getNetworkTimeout();
//OR
long timeout = configuration->getNetworkTimeout();
```

```csharp
int timeout = extendedOptions.NetworkTimeout;
//OR
int timeout = configuration.NetworkTimeout;
```

```swift
configuration.networkTimeout
```

Java

```java
// Request timeout in seconds, default is 10s
Long requestTimeout = configuration.getRequestTimeout(); 
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x49;n C++, the network timeout is represented as a long, while in .NET, it is represented as an int.
:::

Configuring the network timeout is equally straightforward, accomplished in a comparable manner:

:::CodeblockTabs
```cpp
extendedOptions.setNetworkTimeout( timeout );
//OR
configuration->setNetworkTimeout( timeout );
```

```csharp
extendedOptions.NetworkTimeout = timeout;
//OR
configuration.NetworkTimeout = timeout;
```

```swift
configuration.networkTimeout = timeout // TimeInterval.
```

Java

```java
LicenseSpringConfiguration config = LicenseSpringConfiguration
    .requestTimeout(15) // setting timeout to 15s
    .builder()
```
:::

The C++ SDK also allows to set and get the connection timeout, i.e. the value used for CURLOPT\_CONNECTTIMEOUT. It defaults to 7 seconds.

```cpp
extendedOptions.setConnectTimeout( timeout );
//OR
configuration->setConnectTimeout( timeout );
```

## Proxy Settings

Proxy settings are configuration parameters that allow you to route network traffic through an intermediary server, known as a proxy server. Proxy settings are another feature stored within `ExtendedOptions` and `Configuration` that can be accessed with:

:::CodeblockTabs
```cpp
ProxySettings proxy = extendedOptions.getProxySettings();
//OR
ProxySettings proxy = configuration->getProxySettings();
```

```csharp
ProxySettings proxy = extendedOptions.Proxy;
//OR
ProxySettings proxy = configuration.Proxy;
```

Java

```java
String proxyHost = config.getProxyHost();
Integer proxyPort = config.getProxyHost();
String proxyUser = config.getProxyHost();
String proxyPass = config.getProxyHost();
String proxyCertPath = config.getProxyCertPath();
```
:::

Proxy settings can be set as follows:

:::CodeblockTabs
```cpp
extendedOptions.setProxySettings( proxySettings );
```

```csharp
extendedOptions.Proxy = proxySettings;
//OR
configuration.Proxy = proxySettings;
```

```swift
configuration.proxyHost = "..."
configuration.proxyPort = 65535 // UInt16.
```

Java

```java
LicenseSpringConfiguration config = LicenseSpringConfiguration
    .proxyHost("192.168.1.3")
    .proxyPort(3128)
    .proxyUser("test")
    .proxyPass("test")
    .builder()
```
:::

:::hint{type="danger"}
**Exception:&#x20;**&#x41;uthorizationException thrown if authorization fails. To resolve, check and ensure proxy settings are correct.
:::

In the Windows version of the C++ SDK, proxy settings can be automatically fetched through the WinHTTP API.

If the proxy is autoconfigured through a `.pac` file over the network, the SDK reads which proxy is used to reach `api.licensespring.com` or some other custom API URL.

Proxy credentials are read from Windows Credential Manager, and the caller needs to supply the exact Windows Credential target that holds the credentials:

```cpp
LicenseSpring::ProxySettings proxy;
std::string serviceUrl = "https://api.licensespring.com";
std::string credentialTarget = "WindowsProxyCredential"; //depends on the proxy setu
bool throwExceptions = true; // false by default
proxy.fetchProxySettings(serviceUrl, credentialTarget, throwExceptions);
```

## Native Transport Layer Security

The C++ SDK offers the opportunity to enable or disable native TLS for curl.

:::hint{type="info"}
**Note: Schannel&#x20;**&#x69;s the protocol used for Windows, while **Secure Transport&#x20;**&#x69;s utilized for macOS.&#x20;

Before modifying the default settings of the SDK, it's crucial to have a clear understanding of the implications.&#x20;

Make sure to consult the curl documentation for guidance:

[**SSL/TLS Documentation**](https://curl.se/docs/sslcerts.html)

[**SSL/TLS Library Comparison**](https://curl.se/docs/ssl-compared.html)
:::

To enable native TLS for curl, we use:

:::CodeblockTabs
```cpp
extendedOptions.setUseNativeTLS( true );
```

Java

```java
LicenseSpringConfiguration config = LicenseSpringConfiguration
    .sslConfig(sslConfig)
    .builder()
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x49;f set to false, Open SSL will be used.
:::

To later check for whether native TLS is being used:

```cpp
bool enabled = extendedOptions.isNativeTLSEnabled();
```

## Secure Sockets Layer Certificate Verification

Similar to native TLS, the C++ SDK allows developers to decide whether SSL certificate verification is to be enabled or disabled.

:::hint{type="info"}
**Note:&#x20;**&#x42;y default, SSL certificate verification is **enabled**.

**We strongly discourage disabling this option.**

For more information, see the [**SSL Certificate Verification Documentation**](https://curl.se/libcurl/c/CURLOPT_SSL_VERIFYPEER.html).
:::

To disable SSL certificate verification:

```cpp
extendedOptions.enableSSLCheck( false );
```

There is also a checker for whether SSL certificate verification is enabled:

```cpp
bool enabled = extendedOptions.isSSLCheckEnabled();
```


[title] User-Based Licensing
[path] SDKs/Tutorials/Licensing Scenarios/

User-based licensing is a contemporary approach to software or service provisioning, wherein access and usage rights are granted on a per-user basis.&#x20;

Unlike traditional licensing models that focus on the number of devices or installations, user-based licensing centers around the actual individuals who will be utilizing the product or service.&#x20;

This model has gained popularity due to its flexibility and scalability, providing businesses and organizations with a more efficient and cost-effective way to manage their software resources.

By the end of this tutorial, you should understand how to create a login feature by activating a license, how to create a logout feature by deactivating a license, and how to routinely perform online checks on your user-based license from your program.&#x20;

:::hint{type="info"}
When [**Activate License (Online Method)**](docId\:Mt2yGm6CJzh2bumU-Gfww) a **user-based license**, the `license_id` parameter is optional but highly recommended in certain cases:

- If `license_id` is **not provided**, the system will activate the **most recently created license** associated with the specified user.
- If a user is assigned to **multiple licenses**, omitting `license_id` may lead to unintended behavior, as the latest license will be selected automatically.
:::

## Adding a User to a License on the Platform

Email and password of users, can be found on the licenses page. Utilizing a user-based license requires users to be created and assigned to the license.&#x20;

This is done by entering the user-based license, switching to the users tab, and clicking “assign license user”.




![](https://images.prismic.io/licensespring/a9bc07ea-5c64-4403-974b-81e80951b0bd_LicenseAssignUser.png?auto=compress,format "adding user to a license")

## Configuration

Configuration is a set of parameters or settings that are specific to a SDK  and can include elements such as API keys,shared keys or product codes.&#x20;

## Local License

The local license is a copy of the license information that is saved on the end user's local computer. Users who have not activated the license on their end before will not have a local license. By default, the local license is stored: `%USERPROFILE%\AppData\Local\LicenseSpring\”Product Code”\License.key`.

You can read more about the local license file [**here**](https://docs.licensespring.com/sdks/tutorials/best-practices/local-license-file).

The process of activating a license refers to binding a device to a license. On the LicenseSpring platform, activating the license increments the total activations counter within the license.

If a device already has a license, and you try to activate another license on that device, for the same product, that newly activated license will override the existing license, deleting it from the device. This will be on the developer to make sure that they check if a license exists on the device before a new activation:

:::CodeblockTabs
```cpp
auto license = licenseManager->getCurrentLicense();
if( license == nullptr )
    //activate a new license
```

```csharp
var license = licenseManager.CurrentLicense();
if ( license == null )
   //activate a new license
```

```java
License license = licenseManager.getCurrent();
if ( license == null )
  //activate a new license
```

```swift
if manager.currentLicense == nil {
    // activate new license.
}
```

```python
## need to implement getCurrentLicense in python
```

```go
// Go SDK v2
ld, err = license_handler.GetCurrentLicense()
```
:::

## Activation

### Logging In

Creating a login system with the user-based license is straightforward. You can ask the user to input their email and password combination. Once we have the user's credentials, we can then take that email/password combination and use it to activate our user-based license. How the user inputs their credentials is up to you.

:::CodeblockTabs
```cpp
std::string email = "UserEmail@example.com";
std::string password = "UserPassword";
auto licenseId = LicenseID::fromUser( email, password );
auto license = licenseManager->activateLicense( licenseId );
```

```csharp
string email = "UserEmail@example.com";
string password = "UserPassword";
var licenseId = LicenseID.FromUser( email, password );
var license = licenseManager.ActivateLicense( licenseId );
```

```java
String email = "UserEmail@example.com";
String password = "UserPassword";
ActivationLicense licenseId = ActivationLicense.fromUsername( email, password );
License license = licenseManager.activateLicense( licenseId );
```

```swift
let license = try manager.activateLicense(
    user: "UserEmail@example.com",
    password: "UserPassword"
)
```

```python
from licensespring.licensefile.license_manager import LicenseID
from licensespring.licensefile.license_manager import LicenseManager

license_id = LicenseID.from_user(username="email@email.com",password="password")
license = manager.activate_license(license_id) 
```
:::

### Checking a License

It is recommended to perform a local license check at application open to confirm that the local license file belongs to the current device and has not been transferred. It is also useful to check whether the local license file has been tampered with and whether the local license is still valid.  For more information on performing local license checks, see the [**Getting Started Tutorial**](https://app.archbee.com/docs/FbT_Z5Cu33D-LVZx1fRkU/f9WUVI_a_a3MHSrCREa4h).

:::CodeblockTabs
```cpp
license->localCheck(); //Perform a local (offline) check
license->check(); //Perform an online check
```

```csharp
license.LocalCheck(); //Perform a local (offline) check
license.Check(); //Perform an online check
```

```java
license.localCheck(); //Perform a local (offline) check
license = licenseManager.checkLicense( license ); //Perform an online check
```

```swift
try license.localCheck()
try license.fullCheck()
```

```python
license.local_check()
license.check()
```
:::

## Retrieving Details of License User

User data such as email address, first name, last name, license ID, order ID, and order store ID can all be retrieved through the SDK. Initial passwords are also available on your local license file, but once the password has been changed, you will no longer be able to access that data using the LicenseSpring SDK. All this user data is stored and encrypted on your local license file. The SDK allows you to retrieve the data and decrypt it. For more on license encryption/decryption see our tutorial on [**Safety/Security Considerations**](https://docs.licensespring.com/sdks/tutorials/advanced-usage/security).

Here is how to retrieve a "User Data" object that contains such information

:::CodeblockTabs
```cpp
license->licenseUser();
```

```csharp
license.LicenseUser();
```

```java
license.getData();
```

```swift
let user = try license.user // User?.
```

```python
user_info = license.license_user()
print(user_info)

```
:::

## Modifying User Password

We can allow users to change their password. This can be done by the License Manager through the platform, but we can also allow end-users to change their password using our SDK. To change the password, we will require the original/old password and a new, replacement password. If the old password is correct, and the new password is valid, then the user's password will be changed. **Note: this method requires internet connection.**

:::CodeblockTabs
```cpp
license->changePassword( "old_passord", "new_passord" );
```

```csharp
license.ChangePassword( "old password", "new password" );
```

```java
license.getData();//Java requires the Management SDK to be able to change passwords.
LicenseService licenseService = new LicenseService( configuration );
int userId = 123456789;
licenseService.setUserPassword( userId, "new password" );
```

```swift
try license.changePassword(password: "old_pwd", newPassword: "new_pwd")
```

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_user(username="python@gmail.com",password="7t_x3!o9")

license = manager.activate_license(license_id)

license.change_password("7t_x3!o9","12345678")
```
:::

### Initiating Password Reset for First-Time Login

New accounts are created with a temporary, initial password. We can check if a license user is still using an initial password and prompt them to change their password using the following code:

:::CodeblockTabs
```cpp
auto user = license->licenseUser();
if ( user->isInitialPassword() )
{
//Prompt user to change password, use the change password method from the previous code block.
}
```

```csharp
var user = license.LicenseUser();
if ( user.IsInitialPassword)
{
//Prompt user to change password, use the change password method from the previous code block.
}        
```

```java
//Java currently does not have an initialPassword feature.
```

```swift
if license.user?.isInitialPassword == true {
    // Prompt user to change password.
    // Use the change password method from the previous example.
}
```

```python
user_data = license.license_user()

if user_data["is_initial_password"]:
     pass #ask user to change password
```
:::

## Retrieving All Customer-Associated License Users

To return the list of all the license users on every order by some customer use GetCustomerLicenseUsers method of the SDK. This method returns a list of LicenseUser objects that represents all license users associated with the customer.

:::CodeblockTabs
```cpp
auto users = licenseManager->getLicenseUsers( "CustomerEmail@example.com" ); //get users by customer email

//or get them for the owner of current license
//auto customer = license->owner();
//auto users = licenseManager->getLicenseUsers( customer );
```

```csharp
var customer = new Customer( "CustomerEmail@example.com" ); //create Customer object using the email
//var customer = license.Owner();// or get the owner of current license
var users = licenseManager.GetCustomerLicenseUsers( customer );
```

```swift
let users: manager.requestLicenseUsers(for: "customer@example.com") // [User].
```

```python
manager = LicenseManager(conf)

response = manager.get_user_licenses(license_id)


```
:::

## Retrieving multiple licenses of the same product assigned to a single user.

It's possible for a single user to have multiple licenses of the same product assigned to them. In that case, we need to use another identifier to differentiate between different licenses.&#x20;

The license API does that by assigning a 64-bit `license_id` to each license. To avoid collision with the `LicenseID` structure in the SDKs, we also call them server-side license identifiers, or shorter `serverId` .

To retrieve the license identifiers along with the license and user information, use the `GetUserLicenses` method, which returns a list of all license-user pairs assigned to the relevant user.

:::CodeblockTabs
```cpp
std::string username = "sampleUser";
std::string password = "samplePassword";
userLicensesDataVec = licenseManager->getUserLicenses( username, password );
for ( const auto& userLicensesData : userLicensesDataVec )
{ 
    // you can use the vector to create a license picker.
    // the UserLicense class contains license info.
    // the LicenseUser class contains user info.
    std::cout << userLicensesData->userLicense()->serverId() << std::endl; 
    auto user = userLicensesData->licenseUser();
}

std::string serverId = 123456; // pick a server-side license id
auto licenseId = LicenseID::fromUser( username, serverId, password );
auto license = licenseManager::activateLicense( licenseId );

```

```csharp
            string username = "sampleUser";
            string password = "samplePassword";
            UserLicensesData[] userLicensesDataList = _licenseManager.GetUserLicenses(username, password);

            foreach (UserLicensesData userLicensesData in userLicensesDataList)
            {
                // You can use the list to create a license picker.
                // The License property contains license info.
                // The User property contains user info.
                Console.WriteLine(userLicensesData.License.Id);
                var user = userLicensesData.User;
            }

            long serverId = userLicensesDataList.First().License.Id; // Pick a server-side license id
            LicenseID licenseId = LicenseID.FromUser(username, serverId, password);
            ILicense license = _licenseManager.ActivateLicense(licenseId);
```
:::

:::hint{type="warning"}
If you want to allow users to change licenses dynamically, make sure to set a different file name for the license file for different licenses.
:::



## Common Errors

### C++

| **Exception**                            | **Error code**                   | **Definition**                                                                                            |
| ---------------------------------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `ConfigurationException`                 | `eInitializationError`           | Throws in case of something wrong with Configuration. E.g. wrong API or Shared key                        |
| `InvalidCredentialException`             | `eInvalidCredential`             | This exception means that user or password is wrong                                                       |
| `LicenseActivationException`             | `eActivationFailed`              | Rare exception, can arise if activation is limited to some device count or license transfer is prohibited |
| `LicenseNoAvailableActivationsException` | `eLicenseNoAvailableActivations` | Throws when license has already been activated maximum number of times                                    |
| `PasswordChangeNotAllowedException`      | `ePasswordChangeNotAllowed`      | This exception can arise if password change is restricted by company policy                               |

### .Net

| **Exception**                       | **Definition**                                                              |
| ----------------------------------- | --------------------------------------------------------------------------- |
| `InvalidCredentialException`        | This exception means that user or password is wrong                         |
| `CustomerNotFoundException`         | In case customer does not exist                                             |
| `InvalidAuthMethodException`        | Thrown when GetCustomerLicenseUsers method is called for key-based product  |
| `PasswordChangeNotAllowedException` | This exception can arise if password change is restricted by company policy |
| `MissingParametersException`        | If empty string is passed to ChangePassword method                          |


[title] Floating Server
[path] SDKs/Python SDK/

The user has the ability to utilize either a [**Floating Server**](docId\:F7mHPfDNpmaZrTDQ8IyxI)  or a [**Floating Server**](docId\:F7mHPfDNpmaZrTDQ8IyxI):

**Floating Client**:

- This object is responsible for managing the operations on [**Floating Server**](docId\:uzGCwYdxkClUYUsc1Lcsg)&#x20;

**Floating Manager**:

- This object is responsible for managing operations with the [**Floating Server**](docId\:uzGCwYdxkClUYUsc1Lcsg), while also integrating the [**Local License File**](docId\:FkfZHhA-N838tZNrZu0sZ)&#x20;

## Floating Client

### Initialization

To initialize a **Floating Client**, the user must specify the **API protocol** and **domain**.

- **api\_protocol**: Defines the communication protocol between the client and the server (e.g., "http").
- **api\_domain**: Specifies the domain or IP address and port of the Floating Server (e.g., "localhost:8080").
- **hardware\_id\_provider** (optional): Provides the client's hardware ID, which can be used to uniquely identify the client machine.
- **certificate\_chain\_path** (optional, str): The certificate path is provided during provisioning and is only applicable to Floating Server v2 (e.g "path\_to\_chain.chain.pem").
- **verify\_license\_signature&#x20;**(optional, bool): Signature verification, if enforced, is only applicable to Floating Server v2. Default `true`

```python
from licensespring.floating_server import FloatingAPIClient
from licensespring.hardware import HardwareIdProvider

api_client = FloatingAPIClient(api_protocol="http",api_domail="localhost:8080",certificate_chain_path="path_to_pem_file/chain.pem") 
```

### auth

Authenticate

**Parameters**:

- **username** (str): username
- **password** (str): password

```python
from licensespring.floating_server import FloatingAPIClient

api_client = FloatingAPIClient(api_protocol="http", api_domain="localhost:8080",hardware_id_provider=HardwareIdProvider)
api_client.auth(username="admin",password="tetejac")
```

**Return**(dict): Response

### register\_user

Register user

**Parameters**:

- **product** (str,optional): product short code.
- **user** (str,optional): user. Defaults uses hardware id.
- **os\_hostname** (str, optional): os hostname. Defaults to None.
- **ip\_local** (str, optional): ip local. Defaults to None.
- **user\_info** (str, optional): user info. Defaults to None.
- **license\_id** (int, optional)\:license id. Defaults to None.

```python
api_client = FloatingAPIClient(api_protocol="http", api_domain="localhost:8080")

response = api_client.register_user(
    product="lkprod1",
    user="user_1",
    os_hostname="bla",
    ip_local="bla",
    user_info="bla",
    license_id=1728377159207169
)

print(response)
```

**Return**(dict): Response

### **unregister\_user**

Unregister user

**Parameters**

- **product** (str,optional): product short code.
- **user** (str,optional): user. Defaults uses hardware id.
- **license\_id** (int, optional): license id. Defaults to None.

```python
api_client = FloatingAPIClient(api_protocol="http", api_domain="localhost:8080")

response = api_client.unregister_user(product="lkprod1",user="user_1",license_id=1728377159207169)

print(response)
```

**Return**(str): "user\_unregistered"

### **unregister\_all**

Unregister all users

```python
api_client = FloatingAPIClient(api_protocol="http", api_domain="localhost:8080")

api_client.unregister_all()
```

### borrow

Borrow license

**Parameters**

- **product** (str, optional): product short code.
- **user** (str,optional): user. Defaults uses hardware id.
- **borrowed\_until** (str): borrow until date
- **os\_hostname** (str, optional): os hostname. Defaults to None.
- **ip\_local** (str, optional): ip local. Defaults to None.
- **user\_info** (str, optional): user info. Defaults to None.
- **license\_id**(int, optional)\:license id. Defaults to None.

```python
api_client = FloatingAPIClient(api_protocol="http", api_domain="localhost:8080")

response = api_client.borrow(
        product="lkprod1",
        user="user_1",
        borrowed_until="2029-05-06T00:00:00Z",
        os_hostname="bla",
        ip_local="bla",
        user_info="bla",
        license_id=1728377159207169,
    )
  print(response)
```

**Return**(dict): Response

### add\_consumption

Add license consumption

**Parameters**

- **product** (str, optional): product short code
- **consumptions** (int, optional): consumptions. Defaults to 1.
- **max\_overages** (int, optional): max overages. Defaults to None.
- **allow\_overages** (bool, optional): allow overages. Defaults to None.
- **user** (str, optional): user (default uses hardware id)
- **license\_id** (int, optional): license id. Defaults to None.

```python
api_client = FloatingAPIClient(api_protocol="http", api_domain="localhost:8080")

response = api_client.add_consumption(product="fs", consumptions=1)
```

**Return**(dict): Response

### **add\_feature\_consumption**

Add feature consumption

**Parameters**

- **product** (str): product short code
- **feature\_code** (str): feature code
- **user** (str, optional): user (default uses hardware id)
- **consumptions** (int, optional): consumptions. Defaults to 1.
- **license\_id** (int, optional): license id. Defaults to None.

```python
api_client = FloatingAPIClient(api_protocol="http", api_domain="localhost:8080")

response = api_client.add_feature_consumption(product="fs", feature_code="f2", consumptions=1)
```

**Return**(dict): Response

### feature\_register

Register feature

**Parameters**

- **product** (str,optional): product short code&#x20;
- **feature\_code** (str): feature short code
- **user** (str, optional): user (default uses hardware id)
- **license\_id** (int, optional): license id. Defaults to None.
- **borrowed\_until** (str): borrow until (e.g. 2029-05-06T00:00:00Z)
- **os\_hostname** (str, optional): os hostname. Defaults to None.
- **ip\_local** (str, optional): ip local. Defaults to None.
- **user\_info** (str, optional): user info. Defaults to None.

```python
api_client = FloatingAPIClient(api_protocol="http", api_domain="localhost:8080")

response = api_client.feature_register(
        product="fs", feature_code="f1", os_hostname="w", ip_local="1.0", user_info="info"
    )
print(response)
```

**Return**(dict): Response

### **feature\_release**

Feature release

**Parameters**

- **product** (str): product short code
- **feature\_code** (str): feature short code
- **user** (str, optional): user (default uses hardware id)
- **license\_id** (int, optional): license id. Defaults to None.

```python
api_client = FloatingAPIClient(api_protocol="http", api_domain="localhost:8080")

response = api_client.feature_register(
        product="fs", feature_code="f1", os_hostname="w", ip_local="1.0", user_info="info"
    )

response = api_client.feature_release(product="fs", feature_code="f1")
```

**Return**(str): "feature\_released"

### **fetch\_licenses**

List licenses

**Parameters**

- **product** (str,optional): product short code filter

```python
api_client = FloatingAPIClient(api_protocol="http", api_domain="localhost:8080")

response = api_client.fetch_licenses(product="test")
print(response)
```

## Floating Manager

To intialize Floating Manager [**Python SDK Configuration**](docId\:ITdflAhI-s4KNWy1Gersk)  needs to be created. For Floating server you can set **arbitrary&#x20;**&#x76;alues for `shared_key` and `api_key` keys. Signature verification is available in Floating Server v2. To enable it in the SDK, provide the `.pem` certificate path in the Configuration object.

### auth

Authenticate

**Parameters**:

- **username** (str): username
- **password** (str): password

```python
from licensespring.licensefile.config import Configuration
from licensespring.licensefile.floating_manager import FloatingManager

fs_manager = FloatingManager(conf=conf)
fs_manager.auth(username="admin",password="tetejac")
```

**Return**(dict): Response

### register

Register license

**Parameters**:

- **os\_hostname** (str, optional): os hostname. Defaults to None.
- **ip\_local** (str, optional): ip local. Defaults to None.
- **user\_info** (str, optional): user info. Defaults to None.
- **license\_id** (int, optional)\:license id. Defaults to None.

```python
from licensespring.licensefile.config import Configuration
from licensespring.licensefile.floating_manager import FloatingManager

conf = Configuration(
    product=product,
    api_key="arbitrary",
    shared_key="arbitrary",
    file_key="your_file_key",
    file_iv="your_file_iv",
    api_domain="api_domain",
    api_protocol="http/https",
    certificate_chain_path="path_to_chain.pem"
)

fs_manager = FloatingManager(conf=conf)
license = fs_manager.register()
```

**Return**(License): License object

### unregister

Unregister license

**Parameters**

- license\_id (int, optional): license id. Defaults to None.

```python
fs_manager = FloatingManager(conf=conf)
# There are multiple options to unregister a license
# 1. floating client -> this one is documanted
fs_manager.unregister()
# 2.1. license object -> deactivate method
license.deactivate() 
#2.2 license object -> floating release
license.floating_release(False)
```

**Return**(str): "user\_unregistered"

### unregister\_all

Unregister all users

```python
fs_manager = FloatingManager(conf=conf)
fs_manager.unregister_all()
```

### borrow

Borrow license

**Parameters**

- **borrowed\_until** (str): borrow until date
- **os\_hostname** (str, optional): os hostname. Defaults to None.
- **ip\_local** (str, optional): ip local. Defaults to None.
- **user\_info** (str, optional): user info. Defaults to None.
- **license\_id**(int, optional)\:license id. Defaults to None.

```python
fs_manager = FloatingManager(conf=conf)
license = fs_manager.borrow("2031-05-06T00:00:00Z")
# borrow can be also used within the License object
license.floating_borrow("2031-05-06T00:00:00Z")
```

**Return**(License): License object

### is\_online

Checks if floating server is online

**Parameters**

- **throw\_e** (bool, optional): True if you want to raise an exception. Defaults to False.

```python
fs_manager = FloatingManager(conf=conf)
response = fs_manager.is_online()
```

**Raises**:

- **ex**: Exception

**Return**(bool): True if server is online, otherwise False

### **fetch\_licenses**

List licenses

**Parameters**

- **product** (str,optional): product short code filter

```python
fs_manager = FloatingManager(conf=conf)

response = fs_manager.fetch_licenses(product="test")
print(response)
```

**Return**(dict): Response

### Methods supported inside License object

[**Licensefile Setup and Usage**](docId\:VJ8_JhyxrF8N3ZKCAMDy0), [**Licensefile Setup and Usage**](docId\:VJ8_JhyxrF8N3ZKCAMDy0), [**Licensefile Setup and Usage**](docId\:VJ8_JhyxrF8N3ZKCAMDy0), [**Licensefile Setup and Usage**](docId\:VJ8_JhyxrF8N3ZKCAMDy0) are supported with [**Licensefile Setup and Usage**](docId\:VJ8_JhyxrF8N3ZKCAMDy0)  object for **Floating Server.**

[title] C-Interface
[path] SDKs/Tutorials/Getting Started/C++/

The C interface of LicenseSpring's C++ SDK allows using SDK features in C applications. This tutorial will explain how to implement licensing in a C application using the LicenseSpring SDK.

In this article we will look at activating, checking, and deactivating licenses. This functionality can be implemented using the **LSLicenseHandler&#x20;**&#x73;truct. It is a wrapper of C++ **LicenseHandler&#x20;**&#x63;lass and is similar in use. 

## SDK Configuration

To initialize the SDK you will need to fill in your application name and version, product code and either

- API and shared key, or
- OAuth client\_id and client\_secret.

:::hint{type="info"}
OAuth support was added in v7.35.0 of the SDK. See [**OAuth Authorization**](docId\:xhYZAUaL9QY4jerxKilmk)  on how to set up OAuth.
:::

See the [**C++ SDK Configuration and Usage**](docId\:mtXGBTQymb-dOqfxbCqop) on how to retreive credentials.

When you have the necessary values, create the LSConfiguration object.

```c
const char* AppName = "My LicenseSpring Application";
const char* AppVersion = "1.0.0";
// use in case of standard authentication
const char* ApiKey = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
const char* SharedKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
// use in case of OAuth authentication
std::string ClientId = "xxxxxx-xxxxx-yyy";
std::string ClientSecret = "ssssssssssssssssssssssssssssss";

const char* ProductCode = "XX";

LSExtendedOptions* options = CreateLSExtendedOptions();

LSConfiguration* configuration = CreateLSConfiguration(ApiKey, SharedKey, ProductCode, AppName, AppVersion, options);
FreeLSExtendedOptions(options);

// or
// options->setCryptoProviderKey(options, "password for license encryption key generation");
// LSConfiguration* configuration = CreateLSConfigurationOAuth(ApiKey, SharedKey, ProductCode, AppName, AppVersion, options);
// FreeLSExtendedOptions(options);
```

You have to create a **LSExtendedOptions&#x20;**&#x6F;bject even if you don’t intend to change its values. It is necessary to copy the default values to the **LSConfiguration**. Then you can delete the options object.

Now you can create and initialize **LSLicenseHandler&#x20;**&#x75;sing this configuration.

```c
LSLicenseHandler* lh = CreateLSLicenseHandler(configuration);
```

## License Activation

To activate a license, you need its key or user email and password. For information about getting license keys see: [**C++ SDK Configuration and Usage**](docId\:mtXGBTQymb-dOqfxbCqop)

For information about user based licenses see: [**User-Based Licensing**](docId\:xEPx04M3OH_F6s8ylf6mZ)

Using these values, create a **LSLicenseID&#x20;**&#x61;nd call activation method.

```c
LSLicenseID licenseId = CreateLicenseIDfromKey("XXXX-XXXX-XXXX-XXXX"); 
lh->activateLicense(lh, licenseId);
```

## Local License

Make sure that you check if a license exists on the device before a new activation. For more information see: [**C++ SDK Configuration and Usage**](docId\:mtXGBTQymb-dOqfxbCqop)&#x20;

```c
if(!lh->isLicenseExists(lh))
  //activate a new license
```

## License Check

It is recommended to perform a local license check at application start to confirm that the local license file belongs to the current device, has not been tampered with and is still valid. 

Online license check refreshes the local license with the data from LicenseSpring backend.

```c
// local check
// setting verifySignature to true does a signature verification which
// fails if the license file was tampered with
bool verifySignature = true;
lh->checkLicenseLocal(lh, verifySignature);

// online check
LSInstallationFile* pInstallFile = lh->checkLicense( lh );
if( pInstallFile )
    FreeLSInstallationFile( pInstallFile );
```

This method also returns the most recent **LSInstallationFile&#x20;**&#x61;vailable for the license which can be useful for managing software updates. \[TODO: insert link to the article about handling versions]

You can also check for active, valid, enabled, and expired licenses using `isLicenseActive`, `isLicenseValid`, `isLicenseEnabled`, and `isLicenseExpired `methods respectively.&#x20;

## Full Code Sample

Below you can find a code sample that initializes the SDK, retrieves a local license or activates a new one, and performs the necessary checks.

```c
const char* AppName = "My LicenseSpring Application";
const char* AppVersion = "1.0.0";
// use in case of standard authentication
const char* ApiKey = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
const char* SharedKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
// use in case of OAuth authentication
std::string ClientId = "xxxxxx-xxxxx-yyy";
std::string ClientSecret = "ssssssssssssssssssssssssssssss";

const char* ProductCode = "XX";

LSExtendedOptions* options = CreateLSExtendedOptions();

LSConfiguration* configuration = CreateLSConfiguration(ApiKey, SharedKey, ProductCode, AppName, AppVersion, options);
FreeLSExtendedOptions(options);

// or
// options->setCryptoProviderKey(options, "password for license encryption key generation");
// LSConfiguration* configuration = CreateLSConfigurationOAuth(ApiKey, SharedKey, ProductCode, AppName, AppVersion, options);
// FreeLSExtendedOptions(options);

LSLicenseHandler* lh = CreateLSLicenseHandler(configuration);

if(!lh->isLicenseExists(lh))
{
    LSLicenseID licenseId = CreateLicenseIDfromKey("XXXX-XXXX-XXXX-XXXX"); 
    lh->activateLicense(lh, licenseId);
    if(lh->wasError(lh))
   	{
        const char* error = lh->getLastErrorMsg(lh);
        enum LSErrorCode code = lh->getLastError(lh);
        printf("Error occurred. Message: %s Code: %d\n\n", error, code);
   	}
}

bool verifySignature = true;
lh->checkLicenseLocal(lh, verifySignature);
if(lh->wasError(lh))
{
    const char* error = lh->getLastErrorMsg(lh);
   	enum LSErrorCode code = lh->getLastError(lh);
   	printf("Error occurred. Message: %s Code: %d\n\n", error, code);
}

LSInstallationFile* pInstallFile = lh->checkLicense(lh);
if(pInstallFile)
    FreeLSInstallationFile(pInstallFile);

if(lh->wasError(lh))
{
    const char* error = lh->getLastErrorMsg(lh);
   	enum LSErrorCode code = lh->getLastError(lh);
   	printf("Error occurred. Message: %s Code: %d\n\n", error, code);
}
```

## License Deactivation

Deactivating a license unbinds the device from the license, and decrements the number of total activations. Deactivating is done using the following method:

```c
if(lh->deactivateLicense(lh))
    printf("License deactivated successfully.\n");
```

## Common Errors

The license checks can produce the following errors:

| Error                                                                 | Definition                                                                                                                                                         |
| --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `eLicenseDisabled `<br />`eLicenseInactive`<br />`eLicenseExpired`    | License is in invalid state (disabled, epired or inactive)                                                                                                         |
| `eProductMismatchError `                                              | License does not belong to configured product                                                                                                                      |
| `eDeviceError `                                                       | License does not belong to current device                                                                                                                          |
| `eDeviceBlacklisted`                                                  | The device has been blacklisted                                                                                                                                    |
| `eClockTamperedError`                                                 | Detected cheating with system clock                                                                                                                                |
| `eNoInternetError `<br />`eNetworkTimeoutError`<br />`eServerError`   | Connection-related errors: if there's no Internet or an internal server error occured                                                                              |
| `eUnauthorizedClient`<br />`eOAuthRequired`<br />`eOAuthTokenExpired` | Invalid client credentials.<br />License requires OAuth authentication.<br />OAuth token is expired. This shouldn't happen as the SDK keeps track of its lifetime. |


[title] Single Sign-On
[path] SDKs/Tutorials/Advanced Usage/

Single sign-on is a useful feature that allows users to log in to multiple applications and websites with one set of credentials. In this guide, we will explore how to integrate this functionality into your application using the LicenseSpring SDK.

## Prerequisites

1. Completed the [**C++ SDK Configuration and Usage**](docId\:mtXGBTQymb-dOqfxbCqop) and [**User-Based Licensing**](docId\:xEPx04M3OH_F6s8ylf6mZ) tutorials, specifically:
   - Initialized **LicenseManager&#x20;**(or **LicenseHandler**) with your configuration using the appropriate settings.
   - Activated the user-based license of any type.

## SSO Configuration

To implement SSO activation, add a customer account code to the configuration. The account code can be found on your LicenseSpring account under Customer->Customer accounts:

![](https://lh6.googleusercontent.com/nTTJwTqv6tPMKaoSFpNEeILrhgKA07sDYNlvo1yU6nfBftCSohNzNky77nyKelaY4l4cTcC6Ep6nM0X5MVlBSPZ6bGFwH1hj85xfXEx6s9C7vZ5di3NCa1vcDjFWDFNSxgDeOLyT9FonhKW6m_14qA)

When you have this value, set it to the configuration:

:::CodeblockTabs
```cpp
auto configuration = LicenseSpring::Configuration::Create( ApiKey, SharedKey, ProductCode, AppName, AppVersion );
configuration ->setCustomerAccount( "licensespring" );
```

```csharp
var configuration = new Configuration( ApiKey, SharedKey, ProductCode, AppName, AppVersion );
configuration.CustomerAccount = "licensespring";
```

```swift
configuration.customerAccountCode = "licensespring"
```
:::

This value also can be set during the activation process, so you can use multiple customer accounts without reconfiguring the **LicenseManager**.

## Authorization URL

You can choose the authorization method when getting the authorization URL. There are two methods:

- **Token**: Implicit grant which attaches user pool tokens ( id\_token, access\_token, expires\_in, and token\_type ) to the redirect\_uri once the user is verified.
- **Code**: Authorization code grant method where the code query param is attached to the redirect URL instead of id\_token. This code is sent in the request body when doing license activation.

If you do not want to expose user tokens or the redirect URI is too long for your use case, we recommend using the code instead of the token. By default, the SDK returns the URL with the authorization code. To use the authorization token, pass the additional parameter to the **getSSOUrl&#x20;**&#x6D;ethod:

:::CodeblockTabs
```cpp
auto url = licenseManager->getSSOUrl();//customer account was set to configuration, URL with authorization code

auto url = licenseManager->getSSOUrl(“licensespring”);//customer account was not set to configuration, URL with authorization code

auto url = licenseManager->getSSOUrl( std::string(), false );//customer account was set to configuration, URL with authorization token

auto url = licenseManager->getSSOUrl( “licensespring”, false );//customer account was not set to configuration, URL with authorization token
```

```csharp
var url = licenseManager.GetSSOUrl();//customer account was set to configuration, URL with authorization code

var url = licenseManager.GetSSOUrl(“licensespring”);//customer account was not set to configuration, URL with authorization code

var url = licenseManager.GetSSOUrl(null, false);//customer account was set to configuration, URL with authorization token

var url = licenseManager.GetSSOUrl(“licensespring”, false);//customer account was not set to configuration, URL with authorization token
```

```swift
let ssoURL = try manager.requestSSOURL()
```

```go
sso_resp, err := lh.GetSSOUrl(ctx, "customer account", "use oauth code")
```

Java

```java
SSOUrl ssoUrl = licenseManager.getSsoUrl();
```
:::

Note that this method sets the passed customer account to the **LicenseManager&#x20;**&#x63;onfiguration.

### Alternate SSO URLs

The LicenseSpring platform allows you to set alternate SSO URLs, e.g. one for license activation, and one for license borrowing. The URLs differ only in the `redirect_uri` query parameter.

LicenseSpring SDKs expose functions to fetch a list of all available SSO URLs, with the default one being first in the list:

```cpp
std::vector<std::string> ssoUrls = licenseManager->getAllSSOUrls("licensespring");
```

## Authorization

You can open the SSO URL in the system browser or within the application. After the user enters the login credentials, handle the redirect. 

### System Browser

If you are using the system browser, you can implement reopening the application with the redirect URL as a parameter. To make the application open with the redirect link, add a script that edits the registry, enabling your application to handle LicenseSpring URLs, as a part of the installation process.

Here’s an example of edited registry:

![](https://lh3.googleusercontent.com/Nml8mya19FhFSUs4dQVuJmWGYWNxBRbUMHGfaNLmeUgb-inQO5t2Wff0jfl0W3fmKSoOWnlaM0L2Jy9uZ0hobg-v1Ux4pNrRuGm6thQBMt0Yxgs3Y3W8b6ETjUJPWvd-2uMaOswrlnZvjY6chCjFpg)

![](https://lh3.googleusercontent.com/A7D9Tszf5pOKPx-P-bCYZpKpXyDpXj5bMZEt2Ks3z7d0y7pHuDazMDXk4mCyJ8omoQ93hZ6SEwY3gJmaM8J0NjE6E_P7MhIPfxfdBzyymp2JCwjb4kqXPrOHx-pemkk8lfX7XNFe1Qs6n2mlD2vjcw)

### Browsing Within the Application

This functionality can be implemented using various libraries and tools such as Qt WebEngine or .NET WebBrowser control. The goal is to wait until the URL changes and retrieve this redirect link.

To learn more about both approaches, see the SSO sample projects we provide along with C++ and .Net SDKs.

## License Activation

When you have the redirect URL, extract the authorization code or token.

:::CodeblockTabs
```cpp
auto query = QUrlQuery( redirectURL.fragment() );
const QString paramName( "code" ); //or “id_token”
if( query.hasQueryItem( paramName) )
{
  auto authorizationData = query.queryItemValue( paramName );
  //activate the license
}
```

```csharp
Uri query = new Uri( redirectURL);
string authorizationData = HttpUtility.ParseQueryString( myUri.Query ).Get( "code" );//or “id_token”
if( !string.IsNullOrEmpty( authorizationData ) )
  //activate the license
```

```swift
let token = try LicenseManager.extractSSOToken(
    from: "redirect url",
    scheme: "licensespring" // for integrity check.
)
```
:::

Then pass the `authorizationData` value to the activation method. It allows setting the customer account and specifying whether the authorization data is a code or a token.

:::CodeblockTabs
```cpp
auto license = licenseManager->activateLicense(authorizationData);//customer account was set to configuration, authorizationData is a code

auto license = licenseManager->activateLicense(authorizationData, “licensespring”);//customer account was not set to configuration, authorizationData is a code

auto license = licenseManager->activateLicense(authorizationData, “licensespring”, false);//customer account was not set to configuration, authorizationData is a token
```

```csharp
var license = licenseManager.ActivateLicense( authorizationData );//customer account was set to configuration, authorizationData is a code

var license = licenseManager.ActivateLicense( authorizationData, “licensespring” );//customer account was not set to configuration, authorizationData is a code

var license = licenseManager.ActivateLicense( authorizationData, “licensespring”, false );//customer account was not set to configuration, authorizationData is a token
```

```swift
try manager.activateLicense(ssoToken: token)
```
:::

If you want to use an alternate SSO URL, you must pass it's redirect URI to the license activation or license borrowing function:&#x20;

```cpp
// Use QUrl to extract the redirect URI
auto license = licenseManager->activateLicense(authorizationData, "licensespring", true, redirectURI);
```

## Common Errors

This type of license activation can throw the same errors as a regular activation. 

In addition, there are errors specific to single sign-on:

- **SSOException&#x20;**- In case the customer was not found or SSO is not enabled.
- **SSOTokenException&#x20;**- In case the SSO token is invalid or expired.


[title] Time-Limited
[path] SDKs/Tutorials/Licensing Scenarios/License Types/

In this guide, you'll learn how to manage time-limited licenses using the LicenseSpring SDKs.

This includes understanding validity periods, detecting license expiry with methods like "isExpired," implementing local checks, and gaining insights into remaining days for effective software access management.&#x20;

By mastering these strategies, you can enhance your software distribution through precise time-based licensing techniques.

## Prerequisites

1. Completed the [**Getting Started**](docId\:LSFY9tQ3vfq4ROOW9sHkd) Tutorial, including:
   - Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
   - Created a `LicenseID` using either `LicenseID::fromKey` or `LicenseID::fromUser` function, depending on the activation method you prefer.
   - Activated a license of any type.

## Interpreting and Retrieving Validity Period

Upon configuring a new product in LicenseSpring, you gain the ability to set the default validity period for generated license keys.&#x20;

This validity period signifies the duration in days between the initial activation of the license key and its expiration.&#x20;

:::hint{type="info"}
**Note:&#x20;**&#x41; license key can be configured for perpetual validity or restricted within a specific time frame.
:::

### Retrieving Validity Period in Local Time

With our SDK, obtaining the validity period of a license key in your local time zone becomes a seamless process.

The validity period is stored within the `License` object and can be accessed by using the following method:

:::CodeblockTabs
```cpp
tm LicenseSpring::License::validityPeriod()
```

```csharp
DateTime LicenseSpring.License.ValidityPeriod()	
```

```java
LicenseData.LicenseDataBuilder validityPeriod( ZonedDateTime validityPeriod )
```

```swift
license.validityPeriod // Date?
```
:::

### Retrieving Validity Period in UTC

Developers also have the ability to get the validity period in UTC, rather than local time.

This is done with the following:

:::CodeblockTabs
```cpp
tm LicenseSpring::License::validityPeriodUtc()	
```

```csharp
DateTime LicenseSpring.License.ValidityPeriodUTC()	
```

```python
license.validity_period()
```

```java
LicenseData data = license.getData();
ZonedDateTime validityPeriod = data.getValidityPeriod();
```
:::

## How to Verify if a License has Expired&#x20;

By employing our system, you can easily determine whether a license has expired or remains valid.&#x20;

This process empowers you with accurate information to manage software access effectively, ensuring a seamless user experience.

### Utilizing the "isExpired" Method to Check License Expiry

The `isExpired()` method provides an efficient way to check whether a license has reached its expiration date.&#x20;

Our SDKs offer the ability to check the expiration status through the use of the following `License` methods:

:::CodeblockTabs
```cpp
bool LicenseSpring::License::isExpired()
```

```csharp
bool LicenseSpring.License.IsExpired()	
```

```java
boolean isExpired()
```

```swift
license.isExpired
```

```python
license.is_expired()
```
:::

:::hint{type="info"}
**Note:** Our Java SDK's isExpired() method is called on the `LicenseData` object.
:::

### Implementing Local Checks for License Expiry

A local license check involves assessing the validity and expiration status of a software license within the immediate operating environment.&#x20;

By performing checks locally, the software verifies the license's authenticity and expiration status without relying on external connections.

If the local license is expired, the SDKs will throw the following exceptions:

:::CodeblockTabs
```cpp
LicenseStateException
```

```csharp
LicenseExpiredException
```

```java
LicenseExpiredException
```

```python
LicenseStateException
```
:::

See [**License Checks**](docId\:ie-DAh13B4dqxMAQoYgrj) for more information about local license checks.

## Understanding the "Days Remaining" Value

Developers can also access a field within the `License` object that holds the number of days remiaining until the license expires.

This number of days can be retrieved using the following methods, in the current time zone and UTC, respectively:

:::CodeblockTabs
```cpp
int LicenseSpring::License::daysRemaining()
int LicenseSpring::License::daysRemainingUtc()
```

```csharp
int LicenseSpring.License.DaysRemaining()	
int LicenseSpring.License.DaysRemainingUTC()	
```

```java
long daysRemaining()
```

```python
license.days_remaining()
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x54;he Java SDK only offers the ability to retrieve the days remaining in the current time zone.
:::


[title] Management SDK Installation
[path] SDKs/Tutorials/Getting Started/.NET/C# Management SDK/

The LicenseSpring Management SDK can be downloaded at [**.NET/C# Management SDK**](docId\:uw_7zQ0jWh_kutxiqCPcS)

The supported versions are:

- .NET: net5.0, net6.0, net7.0
- .NET Standard: netstandard2.0, netstandard2.1
- .NET Framework: 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8

## Package Content

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/t9m_hLX-e_RP0onXAwQDN_image.png)

After downloading and unzipping the archive, you will find the following items in the **LicenseSpringManagement&#x20;**&#x66;older:

The **bin** folder contains LicenseSpring libraries built for different versions of .Net.

The **documentation** folder contains a full reference of SDK classes.

The **samples** folder contains several sample projects:

- **ASP.NetManagementSample** - an example of an ASP.Net project using Management SDK
- **ManagementConsoleSample**
- **NetCoreManagementSample** -  this and the previous sample provide a basic understanding of SDK functionality and usage
- **UpdateLicenseOfflineSample** - example of generating update files for offline licenses
- **UserBasedLicenseSample** - brief example of creating a user-based license
- **ManagementConfig.cs** file - .contains a class for SDK configuration and is common for the sample projects.

The package also contains the **ReleaseNotes** file.



[title] License Type Options
[path] SDKs/Tutorials/Licensing Scenarios/

LicenseSpring offers a versatile range of license types to cater to different software licensing models. Each license type is designed to accommodate specific business requirements and user scenarios.&#x20;

Here are the four main license types available in LicenseSpring:

1. [**Consumption-Based**](docId\:OZbYAa449bJHMPjTzV2vw)**:&#x20;**&#x43;onsumption licenses are ideal for applications where usage is metered based on certain metrics, such as the number of API calls, data transfer volume, or any other measurable unit. These licenses allow developers to set usage limits and track consumption, ensuring fair and flexible licensing for their users.
2. [**Time-Limited**](docId:3ULJYP37ej-Qs2GG1SbKR)**:&#x20;**&#x54;ime-limited licenses restrict the software's usage to a specified duration. Users can enjoy access to the application for a predetermined period, after which the license expires. Time-limited licenses are commonly used for trial versions, enabling potential customers to explore the software's features before making a purchase decision.
3. [**Subscription**](docId\:O79gCxoa72yQlYJl3BbHq)**:&#x20;**&#x53;ubscription licenses grant users ongoing access to the software for a recurring fee. With subscription licensing, users can enjoy continuous updates, support, and the latest features during the subscription period. This model fosters long-term relationships with customers and provides a steady revenue stream for software vendors.
4. **Perpetual Licenses:&#x20;**&#x50;erpetual licenses offer a one-time purchase of the software, granting users unlimited access without any time restrictions. Once obtained, users can use the software indefinitely, even without active subscriptions or renewals. Perpetual licenses are suitable for customers who prefer a one-time payment model and do not require continuous updates or support.

The type of a license can be retrieved by accessing the following attribute of the `License` object:

:::CodeblockTabs
```cpp
LicenseType LicenseSpring::License::type()
```

```csharp
LicenseType LicenseSpring.License.Type()	
```

```swift
license.licenseType
```

```python
license.license_type()
```

```java
LicenseData data = license.getData();
LicenseType licenseType = data.getLicenseType();
```
:::

To learn more about the fields available for all types of licenses, see: [**License Data**](docId\:hga7feyWOSlQILolwlzqO).

[title] Retrieve Device
[path] Management API/Device/

Retrieve a single device if requesting manager has access permissions to it.

**URL**: `/api/v1/devices/{id}/`

**Method**: `GET`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 1590981949868340,
    "device_variables": [],
    "created_at": "2020-06-02T10:32:54Z",
    "updated_at": "2020-06-02T12:35:17Z",
    "hardware_id": "1C0B-D53D-2A92-9665-9634-1FE5-1326-56DF-5401-63B1-88D5-DB7D-FB02-D440-3760-720D",
    "time_activated": "2020-03-11T10:22:29Z",
    "time_deactivated": null,
    "validity_period": null,
    "device_active": true,
    "type": "desktop",
    "os": "Microsoft Home 10",
    "sdk_build_version": "Java SDK 0.0.1",
    "last_check": "2020-03-13T11:04:45Z",
    "app_ver": "1.0.",
    "hostname": "DESKTOP-2K64QES",
    "ip": "192.168.202.1",
    "external_ip": "46.234.71.160",
    "mac_address": null,
    "is_vm": true,
    "vm_info": "VMware ESX 3",
    "floating_last_seen": null,
    "floating_in_use": false,
    "blacklisted": false,
    "license": {
        "id": 1606461720853199,
        "license_key": null
    },
}
```


[title] List Hourly Activities Actions Stats
[path] Management API/Analytics/Hourly Activities/

List all hourly activities actions stats the requesting manager has access permissions to.

**URL**: `/api/v1/activities-hourly/actions_stats/`

**Method**: `GET`

### Query Parameters:

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on customer account or related to the customer account.

Possible filters:

- `action__in`
  - values can be `consumption`, `f_consumption`, `check`, `activation`, `deactivation`, `activation_offline`, `deactivation_offline`, `trial_key`, `keygen`, `order`, `license_issued`, `change_password`, `customer_license_users`, `floating_release`, `installation_file`, `versions`, `product_details`, `get_device_variables`, `track_device_variables`, `ping`, `single_sign_on`, `floating_borrow`
- `product__in`
- `license__in`
- `status_code__in`
- `ts__*`
  - `*` can be `lte`, `gte`, `lt`, `gt`, `date__lte`, `date__gte`, `date__lt`, `date__gt`
- `status_code__*`
  - `*` can be `lte`, `gte`, `lt`, `gt`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "activation": {
        "succ": 31733,
        "fail": 5557
    },
    ...
}
```


[title] Floating Server V2
[path] SDKs/Java SDK/

# Floating Server v2 Java Client Documentation

## Overview

The Floating Server v2 (FSv2) Java client provides a complete API for managing floating licenses through an on-premises server. It supports license management, user registration/unregistration, feature management, consumption tracking, offline/airgap licensing, and administrative operations.

### Key Concepts

- **Register/Unregister** replaces Activate/Deactivate — registering a user to a license is the FSv2 equivalent of activating a floating license
- `getLicenseById` returns full license state including `floatingInUseDevices`, `isValid`, `isLicensed`, `licenseActive`, and `licenseEnabled`
- `getLicenseUsers` returns the list of currently registered users with their borrow status — use this to verify if a user is already registered
- `getLicenseFeatures` returns registered feature users
- FSv1 and FSv2 are separate implementations — V1 proxy endpoints are not available on the V2 server

## Getting Started

```java
ProxyConfiguration proxyConfiguration =
    ProxyConfiguration.builder()
        .host("localhost")
        .port(8080)
        .proxyUser("admin")
        .proxyPass("admin")
        .product("<productCode>")
        .proxyCertPath("path/to/certificate-chain.pem")
        .build();
ProxyFloatingService service = new ProxyFloatingService(proxyConfiguration);
```

### Typical Integration Flow

```java
// 1. Get available licenses
List<LicenseData> licenses = service.getLicenses();
LicenseData license = licenses.get(0);
Long licenseId = license.getId();
// 2. Register a user to a license (equivalent to "activate")
RegisterUserToLicenseRequest req = RegisterUserToLicenseRequest.builder()
    .email("user@example.com")
    .username("user1")
    .build();
LicenseData updatedLicense = service.registerUserToLicenseV2(licenseId, req);
// 3. Check license state — floatingInUseDevices shows active registrations
LicenseData licenseState = service.getLicenseById(licenseId);
System.out.println("In-use devices: " + licenseState.getFloatingInUseDevices());
System.out.println("Is valid: " + licenseState.getIsValid());
// 4. Verify registered users
List<FloatingUserResponse> users = service.getLicenseUsers(licenseId);
for (FloatingUserResponse user : users) {
    System.out.println(user.getUsername() + " - borrowed until: " + user.getBorrowedUntil());
}
// 5. Re-register before floating_timeout expires (periodic check-in)
service.registerUserToLicenseV2(licenseId, req);
// 6. Release when done
UnregisterUserFromLicenseRequest unreg = UnregisterUserFromLicenseRequest.builder()
    .email("user@example.com")
    .username("user1")
    .build();
service.unregisterUserFromLicenseV2(licenseId, unreg);
```

## Authentication Methods

### login

Authenticates a user with the floating server.

```java
public LoginResponse login(LoginRequest payload) throws LicenseSpringException
```

**Parameters:**

- payload (LoginRequest): Login credentials containing username and password
  **Returns:** LoginResponse - Authentication response containing token and user information

### changePassword

Updates the password for a user on the floating server.

```java
public ChangePasswordResponse changePassword(ChangePasswordRequest payload) throws LicenseSpringException
```

**Parameters:**

- payload (ChangePasswordRequest): Contains username, old password, and new password
  **Returns:** ChangePasswordResponse - Response indicating success or failure

### setInitialPassword

Sets the initial password for a newly created user.

```java
public InitialPasswordResponse setInitialPassword(InitialPasswordRequest payload) throws LicenseSpringException
```

**Parameters:**

- payload (InitialPasswordRequest): Contains username and new password
  **Returns:** InitialPasswordResponse - Response confirming password was set

### getMe

Retrieves the current authenticated user's information.

```java
public MeResponse getMe() throws LicenseSpringException
```

**Returns:** MeResponse - Current user details

## License Management Methods

### getLicenses

Retrieves all licenses for the configured product.

```java
public List<LicenseData> getLicenses() throws LicenseSpringException
```

**Returns:** List\<LicenseData> - List of all licenses for the product (empty list if none found)

### getLicenseById

Retrieves detailed information for a specific license by ID. Use this to check the current state of a license including how many floating slots are in use.

```java
public LicenseData getLicenseById(Long id) throws LicenseSpringException
```

**Parameters:**

- id (Long): The license identifier
  **Returns:** LicenseData - Complete license object with details including:
- `floatingInUseDevices` — number of currently registered users
- `isValid` — whether the license is valid
- `isLicensed` — whether the license has a valid assignment
- `licenseActive` — whether the license is active
- `licenseEnabled` — whether the license is enabled
- `floatingUsers` — maximum concurrent floating users allowed
- `floatingTimeout` — timeout in minutes before registration expires
- `expired` — whether the license has expired (server-side check)

### addLicenseV2

Activates a product license on the floating server.

```java
public AddLicenseResponse addLicenseV2(AddLicenseParams params) throws LicenseSpringException
```

**Parameters:**

- params (AddLicenseParams): License activation parameters containing the license key
  **Returns:** AddLicenseResponse - Activation result details

### removeLicenseById

Removes a license from the floating server by ID.

```java
public RemoveLicenseResponse removeLicenseById(Long id) throws LicenseSpringException
```

**Parameters:**

- id (Long): The license identifier to remove
  **Returns:** RemoveLicenseResponse - Response message indicating success

## User Registration Methods

### registerUserToLicenseV2

Registers a user to a specific license. This is the FSv2 equivalent of activating a floating license — it reserves a floating slot for the user.

```java
public LicenseData registerUserToLicenseV2(Long licenseId, RegisterUserToLicenseRequest payload) throws LicenseSpringException
```

**Parameters:**

- licenseId (Long): The license identifier
- payload (RegisterUserToLicenseRequest): User registration details (email, username)
  **Returns:** LicenseData - Updated license data after user registration
  **Note:** Re-calling this method for an already-registered user acts as a check-in, resetting the floating timeout.

### unregisterUserFromLicenseV2

Unregisters a user from a specific license, freeing up a floating slot.

```java
public void unregisterUserFromLicenseV2(Long licenseId, UnregisterUserFromLicenseRequest payload) throws LicenseSpringException
```

**Parameters:**

- licenseId (Long): The license identifier
- payload (UnregisterUserFromLicenseRequest): User unregistration details

### getLicenseUsers

Retrieves the list of currently registered users for a license. Use this to verify if a specific user is already registered, check borrow status, or get the full list of active floating users.

```java
public List<FloatingUserResponse> getLicenseUsers(Long licenseId) throws LicenseSpringException
```

**Parameters:**

- licenseId (Long): The license identifier
  **Returns:** List\<FloatingUserResponse> - List of registered users, each containing:
- `id` — user registration ID
- `email` — user email
- `username` — username
- `licenseId` — associated license ID
- `maxActivations` — maximum activations for this user
- `timesActivated` — current activation count
- `borrowedUntil` — borrow expiration timestamp (null if not borrowed)
- `createdAt` / `updatedAt` — timestamps

### unregisterAllUsersFromLicense

Unregisters all users from a license at once.

```java
public MessageResponse unregisterAllUsersFromLicense(Long licenseId) throws LicenseSpringException
```

**Parameters:**

- licenseId (Long): The license identifier
  **Returns:** MessageResponse - Confirmation message

### borrowLicenseV2

Borrows a license for offline use with specified expiration time.

```java
public BorrowLicenseResponse borrowLicenseV2(Long licenseId, BorrowLicenseParams payload) throws LicenseSpringException
```

**Parameters:**

- licenseId (Long): The license identifier
- payload (BorrowLicenseParams): Borrow parameters containing username and borrowedUntil timestamp
  **Returns:** BorrowLicenseResponse - Borrow operation result
  **Description:** Borrows a license slot for offline usage. The borrowedUntil timestamp is converted to UTC and formatted as ISO offset date-time.

## Server User Management Methods

### addUser

Adds a new admin/operator user to the floating server.

```java
public AddUserResponse addUser(AddUserRequest payload) throws LicenseSpringException
```

**Parameters:**

- payload (AddUserRequest): User details (email, username, password, role)
  **Returns:** AddUserResponse - Response containing added user information

### getUsers

Retrieves all server users (admin/operator accounts).

```java
public List<UserResponse> getUsers() throws LicenseSpringException
```

**Returns:** List\<UserResponse> - All server user accounts

### removeUser

Removes a server user by ID.

```java
public RemoveUserResponse removeUser(Long userId) throws LicenseSpringException
```

**Parameters:**

- userId (Long): The user ID to remove
  **Returns:** RemoveUserResponse - Response confirming user removal

## Feature Management Methods

### registerFeatureForUserV2

Registers a feature allocation for a user under a specific license.

```java
public RegisterFeatureForUserResponse registerFeatureForUserV2(Long licenseId, RegisterFeatureForUserRequest payload) throws LicenseSpringException
```

**Parameters:**

- licenseId (Long): The license identifier
- payload (RegisterFeatureForUserRequest): Feature registration details (user and feature code)
  **Returns:** RegisterFeatureForUserResponse - Registration result

### unregisterFeatureForUserV2

Releases a feature allocation for a user under a specific license.

```java
public void unregisterFeatureForUserV2(Long licenseId, UnregisterFeatureForUserRequest payload) throws LicenseSpringException
```

**Parameters:**

- licenseId (Long): The license identifier
- payload (UnregisterFeatureForUserRequest): Feature unregistration details (user and feature code)

### getLicenseFeatures

Retrieves the list of registered feature users for a license. Use this to check which users have which features registered.

```java
public List<FloatingFeatureUserResponse> getLicenseFeatures(Long licenseId) throws LicenseSpringException
```

**Parameters:**

- licenseId (Long): The license identifier
  **Returns:** List\<FloatingFeatureUserResponse> - List of feature registrations, each containing:
- `id` — registration ID
- `email` — user email
- `username` — username
- `featureCode` — the registered feature code
- `licenseId` — associated license ID
- `createdAt` / `updatedAt` — timestamps

### releaseAllFeaturesFromLicense

Releases all feature allocations from a license.

```java
public MessageResponse releaseAllFeaturesFromLicense(Long licenseId) throws LicenseSpringException
```

**Parameters:**

- licenseId (Long): The license identifier
  **Returns:** MessageResponse - Confirmation message

## Consumption Tracking Methods

### addConsumptionToLicenseV2

Adds consumption data to a license.

```java
public AddConsumptionToLicenseResponse addConsumptionToLicenseV2(Long licenseId, AddConsumptionToLicenseRequest payload) throws LicenseSpringException
```

**Parameters:**

- licenseId (Long): The license identifier
- payload (AddConsumptionToLicenseRequest): Consumption details to record
  **Returns:** AddConsumptionToLicenseResponse - Consumption recording result

### addConsumptionToFeatureV2

Adds consumption data to a specific feature within a license.

```java
public AddConsumptionToFeatureResponse addConsumptionToFeatureV2(Long licenseId, AddConsumptionToFeatureRequest payload) throws LicenseSpringException
```

**Parameters:**

- licenseId (Long): The license identifier
- payload (AddConsumptionToFeatureRequest): Feature consumption details to record
  **Returns:** AddConsumptionToFeatureResponse - Feature consumption recording result

## Offline Licensing Methods

### offlineActivationGenerate

Generates an offline activation request for processing without network connectivity.

```java
public OfflineActivationResponse offlineActivationGenerate(OfflineActivationRequest payload) throws LicenseSpringException
```

**Parameters:**

- payload (OfflineActivationRequest): Offline activation request details
  **Returns:** OfflineActivationResponse - Generated activation data

### offlineActivationUpload

Uploads a completed offline activation response.

```java
public OfflineActivationResponse offlineActivationUpload(OfflineActivationRequest payload) throws LicenseSpringException
```

**Parameters:**

- payload (OfflineActivationRequest): Completed activation data to upload
  **Returns:** OfflineActivationResponse - Upload confirmation

### offlineDeactivationGenerate

Generates an offline deactivation request.

```java
public OfflineDeactivationResponse offlineDeactivationGenerate(OfflineDeactivationRequest payload) throws LicenseSpringException
```

**Parameters:**

- payload (OfflineDeactivationRequest): Offline deactivation request details
  **Returns:** OfflineDeactivationResponse - Generated deactivation data

### offlineUpdate

Processes an offline license update.

```java
public OfflineActivationResponse offlineUpdate(OfflineActivationRequest payload) throws LicenseSpringException
```

**Parameters:**

- payload (OfflineActivationRequest): Offline update data
  **Returns:** OfflineActivationResponse - Update result

## Air-Gapped Licensing Methods

### airgapGenerate

Generates an air-gapped activation signature.

```java
public AirgapActivationResponse airgapGenerate(AirgapActivationRequest payload) throws LicenseSpringException
```

**Parameters:**

- payload (AirgapActivationRequest): Air-gap generation request
  **Returns:** AirgapActivationResponse - Generated signature

### airgapActivate

Activates an air-gapped license.

```java
public AirgapActivationResponse airgapActivate(AirgapActivationRequest payload) throws LicenseSpringException
```

**Parameters:**

- payload (AirgapActivationRequest): Air-gap activation data
  **Returns:** AirgapActivationResponse - Activation result

### airgapDeactivateGenerate

Generates an air-gapped deactivation request.

```java
public AirgapDeactivationResponse airgapDeactivateGenerate(AirgapDeactivationRequest payload) throws LicenseSpringException
```

**Parameters:**

- payload (AirgapDeactivationRequest): Air-gap deactivation request
  **Returns:** AirgapDeactivationResponse - Generated deactivation data

### airgapDeactivate

Processes an air-gapped deactivation.

```java
public AirgapDeactivationResponse airgapDeactivate(AirgapDeactivationRequest payload) throws LicenseSpringException
```

**Parameters:**

- payload (AirgapDeactivationRequest): Air-gap deactivation data
  **Returns:** AirgapDeactivationResponse - Deactivation result

## Server Configuration Methods

### getConfig

Retrieves the current floating server configuration.

```java
public CloudConfigResponse getConfig() throws LicenseSpringException
```

**Returns:** CloudConfigResponse - Current server configuration

### updateConfig

Updates the floating server configuration.

```java
public CloudConfigResponse updateConfig(CloudConfigUpdateRequest payload) throws LicenseSpringException
```

**Parameters:**

- payload (CloudConfigUpdateRequest): Configuration changes to apply
  **Returns:** CloudConfigResponse - Updated configuration

### getSyncSettings

Retrieves the current sync settings.

```java
public SyncSettingsResponse getSyncSettings() throws LicenseSpringException
```

**Returns:** SyncSettingsResponse - Current sync configuration

### setSyncSettings

Updates the sync settings.

```java
public SyncResponse setSyncSettings(SyncSettingsRequest payload) throws LicenseSpringException
```

**Parameters:**

- payload (SyncSettingsRequest): Sync settings to apply
  **Returns:** SyncResponse - Updated sync status

### triggerSync

Triggers a manual synchronization with the LicenseSpring platform.

```java
public SyncResponse triggerSync() throws LicenseSpringException
```

**Returns:** SyncResponse - Sync result

## Health Check

### serverHealthy

Checks if the floating server is running and responsive.

```java
public boolean serverHealthy() throws LicenseSpringException
```

**Returns:** boolean - true if the server is healthy

## FSv1 vs FSv2 Compatibility

FSv1 and FSv2 are separate implementations with different API contracts:

- **Activate license:** `register()` → `registerUserToLicenseV2()`
- **Deactivate license:** `unregister()` → `unregisterUserFromLicenseV2()`
- **Check license:** `getLicense()` → `getLicenseById()`
- **Check registered users:** N/A → `getLicenseUsers()` *(new in v2)*
- **Check feature users:** N/A → `getLicenseFeatures()` *(new in v2)*
- **Borrow:** `borrow()` → `borrowLicenseV2()`

**Add consumption:** `addConsumption()` → `addConsumptionToLicenseV2()`
FSv1 proxy endpoints are not available on the V2 server. The SDK's `ProxyFloatingService` automatically routes to the correct endpoints based on the detected API version.
**Note:** All v2 methods throw `UnsupportedOperationException` if called against a v1 server, and vice versa.



[title] SDK Distribution and Licensing
[path] SDKs/C++ SDK/

## SDK License

Since v7.34.0 the LicenseSpring C++ SDK is licensed under the LicenseSpring Compiled SDK License Agreement (LCSLA).

```markdown
LicenseSpring Compiled SDK License Agreement (LCSLA)

Preamble:
This LicenseSpring Compiled SDK License Agreement (LCSLA) governs the use, distribution, and modification of the compiled binaries for the LicenseSpring SDKs. These SDKs, including those for C++, Java, and .NET, are designed to facilitate integration with LicenseSpring’s license management service. By accessing or using the SDK binaries, you agree to the terms and conditions set forth in this agreement.

1. Permissions:

	* You are permitted to use the compiled SDK binaries provided by LicenseSpring solely for the purpose of integrating your products with the LicenseSpring service.
	* You may create derivative works that rely on or incorporate the SDK binaries, provided such derivative works are used exclusively as part of the LicenseSpring service.

2. Distribution:

	* You may distribute software that integrates or incorporates the SDK binaries, provided the software interacts directly with the LicenseSpring service.
	* Distribution of the SDK binaries, in their original or modified form, is only allowed in conjunction with your own software that integrates with LicenseSpring.
	* Distributed versions, including derivative works, may not be:
		* Provided as part of a hosted or cloud-based service that allows others to access the SDK’s functionality without interacting directly with the LicenseSpring service.
		* Integrated into other services that compete with or do not use the LicenseSpring service.

3. Usage Restrictions:

	* The SDK binaries, in their original or modified form, may only be used as part of the LicenseSpring service.
	* You are prohibited from using the SDK binaries independently or as part of any service that does not interact with the LicenseSpring service.

4. Prohibited Actions:

	* You may not reverse engineer, decompile, or disassemble the SDK binaries, except as expressly permitted by applicable law.
	* You must not modify, remove, or obscure any license notices, copyright notices, or other proprietary notices from the SDK binaries without permission from Cense Data Inc.

5. Contributions and Feedback:

	* By submitting suggestions, improvement ideas, feature requests, or any other feedback ("Contributions"), you grant LicenseSpring a perpetual, worldwide, royalty-free, irrevocable license to use, reproduce, modify, distribute, and incorporate the Contributions into the SDK or any other products or services of LicenseSpring.
	* LicenseSpring retains sole ownership and rights to the SDK binaries and any incorporated Contributions.

6. Termination:
	* Any violation of these terms will result in the automatic termination of your rights under this license.
	* Upon termination, you must cease all use and distribution of the SDK binaries and destroy all copies in your possession.

7. Disclaimer of Warranty and Liability:

	* Permission to use, copy, and/or distribute the SDK binaries for any purpose with or without fee is hereby granted under the conditions outlined above.

	THE SOFTWARE IS PROVIDED "AS IS" AND LICENSESPRING DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. LICENSESPRING SHALL NOT BE LIABLE FOR ANY DAMAGES ARISING OUT OF OR RELATED TO THE USE OR PERFORMANCE OF THE SOFTWARE.

Copyright 2018-2025 Cense Data Inc DBA LicenseSpring
Contact: support@licensespring.com
```

## Dependencies

### libcurl - curl license, inspired by MIT

libcurl library to facilitate secure HTTPS communication with the LicenseSpring server.The use of libcurl, with its ease of implementation and robust security features, significantly enhances the application's capability to  interact with LicenseSpring's API. Its comprehensive support for HTTPS ensures encrypted and secure data transmission

### Boost - Boost Software License

Boost library is used to significantly enhance the performance and capabilities (using of multithreading) of our LicenseSpring integration.&#x20;

**The SDK uses only header-only boost libraries.**

### OpenSSL - Apache License v2 since OpenSSL 3.0

In our integration with LicenseSpring, OpenSSL serves as a foundational component, particularly for cryptography and secure SSL/TLS communications. By leveraging OpenSSL, we ensure that all interactions  with the LicenseSpring server are conducted over secure channels

### libcrypto

libcrypto is part of OpenSSL, which is a robust, full-featured open-source toolkit&#x20;
implementing the Secure Sockets Layer (SSL) and Transport Layer Security
&#x20;(TLS) protocols as well as a general-purpose cryptography library.

### nlohmann/json - MIT license

&#x20;JSON for Modern C++, is a popular JSON library used for parsing, serializing, and manipulating JSON data sent by LicenseSpring server.&#x20;

### Catch2 - Boost Software License

Catch2 is a modern, C++-native, header-only, test framework for unit&#x20;
tests, TDD (Test-Driven Development), and BDD (Behavior-Driven&#x20;
Development).

Versions currently being used in latest SDK:

```markdown
libcurl 8.12.1
boost 1.76.0
openssl 3.4.1
libcrypto 3.4.1
libykpiv 2.7.1
```

## Dependency Licenses

Aggregated Licenses from open source dependencies present within the LicenseSpring C++ SDK.&#x20;

All dependency license agreements can also be found in the released SDK archives.

::File[Aggregated Licenses from open source dependencies present within the LicenseSpring C++ SDK]{src="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/IZWYBcXnIG5RwjDVQ2oOO_licenses.zip" signedSrc="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/IZWYBcXnIG5RwjDVQ2oOO_licenses.zip?AWSAccessKeyId=AKIAYQNQCIXNIQWBC56C&Expires=1701770527&Signature=qS0NWQ3MmqW57rTB1mLGla9%2F4ew%3D" label="licenses.zip" isUploading="false"}




[title] Python SDK
[path] SDKs/

## LicenseSpring Python Library:

The LicenseSpring Python Library provides convenient access to the LicenseSpring API from
applications written in the Python language.

### Installation:

Install `licensespring` library:

```text
pip install licensespring
```

Requires: **Python >=3.10**

### Demo application

You can test the SDK using the [**demo app**](https://sdk.licensespring.com/Python%20SDK/v3.6.0/sample_app.zip). All required files and setup instructions are included in the provided ZIP folder.


[title] Custom License Storage
[path] SDKs/Tutorials/Advanced Usage/

While a default location is predefined for the local license file, the flexibility to modify its location exists within LicenseSpring's C++ and .NET SDK.&#x20;

This versatility allows for storing the license file in various alternative locations, including databases, Windows registries, or remote servers.&#x20;

:::hint{type="info"}
**Note:&#x20;**&#x54;his guide operates under the assumption that SQLite3 is properly installed on the reader's device, and a fundamental understanding of SQL is present.

If you require more information about SQLite, it's recommended to refer to their [**official documentation**](https://www.sqlite.org/docs.html) for comprehensive insights.
:::

## Prerequisites

1. Completed the [**Getting Started**](docId\:LSFY9tQ3vfq4ROOW9sHkd) Tutorial, specifically:
   - Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
   - Created a `LicenseID` using either `LicenseID::fromKey` or `LicenseID::fromUser` function, depending on the activation method you prefer.
   - Implemented basic license management, including license activations, deactivations, and both online and local license checks.&#x20;

## Default License File Encryption

In the `LicenseStorage` interface, the encryption and decryption of the license file are executed by invoking basic functions within the C++ and .NET SDK.&#x20;

Encryption takes place during the activation and initial storage of the license, utilizing the `activateLicense()` method on the `LicenseManager` object.

Decryption of the license file is done when either `reloadLicense()` or `getCurrentLicense()` are called, also on the `LicenseManager` object.

:::hint{type="info"}
**Note:&#x20;&#xD;**&#x54;he methods `loadLicense()` and `saveLicense()` present in `LicenseFileStorage` are responsible for reading and writing the license file, without involving encryption or decryption. Encryption is exclusively carried out during license activation and retrieval processes.
:::

## Adding License File to a Database

Once you've established the derived class and successfully implemented the `loadLicense()`, `saveLicense()`, and `clear()` methods, the next step involves customizing the default file location.&#x20;

To accomplish this, when instantiating the `LicenseManager` object, you should provide a second parameter. This additional parameter allows you to specify a different storage location for the local license.&#x20;

By default, the local license is stored in a file. To check this default location, see our [**Local License File**](docId\:FkfZHhA-N838tZNrZu0sZ) tutorial.

:::CodeblockTabs
```cpp
licenseManager->create( configuration, storage );
```

Java

```java
licenseManager.initialize(configuration, repository);
```
:::

:::hint{type="info"}
**Reminder:&#x20;**&#x45;ncryption operations are conducted independently of the `loadLicense()` and `saveLicense()` methods. These methods do not require encryption or decryption procedures.
:::

## License File Terminology

### **LicenseFileStorageBase:**

`LicenseFileStorageBase` serves as the foundational class responsible for storing licenses in a file and implementing the `LicenseStorage` interface. It is important to note that this class does not incorporate any mechanisms for ensuring synchronized access to files, rendering it unsuitable for concurrent multi-threaded operations.

### LicenseFileStorage

Derived from `LicenseFileStorageBase`, the `LicenseFileStorage` Class inherits its characteristics and functionality, but with the added feature of thread-safe file operations. This class stands as the default choice for license storage, as it guarantees safe file handling even in multi-threaded scenarios.

### LicenseFileStorageEx

A further specialization of the `LicenseFileStorageBase` class is `LicenseFileStorageEx`. This advanced license file storage variant is specifically designed for interprocess applications. It employs a synchronization mechanism using a mutex provided by the Boost library, ensuring both thread and process safety. This class is ideal for scenarios where concurrent access from multiple threads and processes is required while maintaining the integrity of file operations.

[title] Licensefile Setup and Usage
[path] SDKs/Python SDK/

## Licensefile Setup

### Key and IV Setup

To use licensefile inside a python SDK you should first setup your key and IV. Key and IV are used inside Python SDK for encryption and decryption process inside licensefile. This process is only required **once** at the setup.

```python
from licensespring.licensefile.default_crypto import DefaultCryptoProvider

password = "YOUR_PASSWORD"
salt = "YOUR_SALT"


crypto = DefaultCryptoProvider()

key = crypto.derive_key(password=password,salt=salt)
iv = crypto.generate_random_iv()

```

## Configuration Setup

After you have successfully setup your key and IV you should setup your Configuration.&#x20;

```python
from licensespring.licensefile.config import Configuration
#from licensespring.hardware import HardwareIdProviderSource
#The commented hardware_id_provider will become the default in the next major version of the SDK
#we advise using HardwareIdProviderSource!
conf = Configuration(product="your_product_key",api_key="your_api_key",
                   shared_key="your_shared_key",file_key=key,file_iv=iv,
                   is_guard_file_enabled=True,
                   #hardware_id_provider=HardwareIdProviderSource)


                              
```

### Configuration Attributes

- **api\_key** (str,optional): Your unique API key used for authentication with the licensing server.&#x20;
- **shared\_key** (str,optional): A shared secret key used alongside the API key for enhanced security during the license verification process.
- **file\_key** (str): The encryption key used for securing license files on the client side.&#x20;
- **file\_iv** (str): The initialization vector for the encryption algorithm. This complements the **file\_key** for encrypting and decrypting license files.&#x20;
- **hardware\_id\_provider** (object, optional): The provider class used for generating a unique hardware ID. This ID helps in binding the license to specific hardware. Defaults to **HardwareIdProvider**.
- **verify\_license\_signature** (bool, optional): A boolean flag indicating whether the license's digital signature should be verified. Defaults to **True** for enhanced security.
- **signature\_verifier** (object, optional): The class responsible for verifying the digital signature of licenses. Defaults to **SignatureVerifier**.
- **api\_domain** (str, optional): The domain name of the API server with which the licensing operations are performed. Defaults to **"api.licensespring.com"**.
- **api\_version** (str, optional): The version of the API to use for requests. This allows for compatibility with different versions of the licensing API. Defaults to **"v4"**.
- **filename** (str, optional): The default filename for saved license files. This can be customized as needed. Defaults to **"License"**.
- **file\_path** (str, optional): The path where license files should be saved on the client system. If not specified, a default location is used.
- **grace\_period\_conf** (int, optional): The number of hours to allow as a grace period for  Defaults to 24 hours.
- **is\_guard\_file\_enabled** (bool): Enables guard protection for offline licenses if set to True.
- **air\_gap\_public\_key&#x20;**(str, optional): Air gap public key
- **client\_id (str, optional)**: Client ID for OAuth authorization purposes
- **client\_secret (str, optional)**: Client Secret for OAuth authorization purposes
- **certificate\_chain\_path (str, optional)**: path to `.pem` file used in provisioning (e.g "path\_to\_chain.pem")

:::hint{type="warning"}
* We advise for  **hardware\_id\_provider&#x20;**&#x74;o use a newly developed  [**Python Hardware (Device) IDs**](docId\:ORDujMleQE_0SSSxxa3bQ)  provider.
* On the **next major** version release **HardwareIdProviderSource** will be set as default **hardware\_id\_provider**
* if both **API keys** and **OAuth** are specified in **Configuration**, SDK will use OAuth for authorization
:::

## LicenseID

Represents a mechanism for license identification and activation, supporting both key-based and user-based activations.

### Methods

- **from\_key(cls, key) -&#x20;**&#x43;lass method to create a **LicenseID&#x20;**&#x69;nstance for key-based activation
- **from\_user(cls, username, password) -&#x20;**&#x43;lass method to create a **LicenseID&#x20;**&#x69;nstance for user-based activation.

### Key-Based Setup

```python
from licensespring.licensefile.license_manager import LicenseID

license_id = LicenseID.from_key("your_license_key")            
```

### User-Based Setup

```python
from licensespring.licensefile.license_manager import LicenseID

license_id = LicenseID.from_user(username="email@email.com",password="password")                         
```

## LicenseManager

Manages license activations, supporting a variety of parameters to accommodate different licensing scenarios.

```python

from licensespring.licensefile.license_manager import LicenseManager

manager = LicenseManager(conf)
                                
```

### Configuration parametres

- **conf&#x20;**(Configuration): A configuration object

### Methods

### Getters

```python
manager.is_license_file_corrupted() # Checks if licensefile is corrupted 
manager.data_location() # Get licensefile location 
manager.license_file_name() # Get licensefile name  
manager.current_config() # Get current configuration                   
```

### **activate\_license**

Activates a license with the license server and updates local license data.Returns an instance of the **License**

**Key-based**

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H6QM-6H5R-ZENJ-VBLK")

license = manager.activate_license(license_id)
                                
```

**User-based&#x20;**

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_user(username="python@gmail.com",password="7t_x3!o9")

license = manager.activate_license(license_id,unique_license_id=1723642193958949)
                          
```

:::hint{type="info"}
There is optional `unique_license_id` which specifies `license_id`. It if prefered that given argument is used when activating user based licenses
:::

### load\_license

Loads the license file and sets attributes for the **LicenseData&#x20;**&#x69;nstance. Returns an instance of the **License** class reflecting the loaded license.

```python
manager = LicenseManager(conf)

license = manager.load_license()

                                
```



### **reconfigure**

Change the current configuration

```python
manager = LicenseManager(conf)

manager.reconfigure(
        Configuration(
            product="lkprod2",
            api_key="new_key",
            shared_key="new_key",
            file_key="file_key",
            file_iv="file_iv",
            file_path="bb",
            grace_period_conf=12,
            is_guard_file_enabled=True,
        )
    )

                                
```

### clear\_local\_storage

Delete all files for given product

```python
manager = LicenseManager(conf)
license_id = LicenseID.from_key("H6QM-6H5R-ZENJ-VBLK")  
license = manager.activate_license(license_id)  
manager.clear_local_storage()

                                
```

### set\_data\_location

Set data location

**Parameters**:

- **path** (str): new data location path

```python
manager = LicenseManager(conf)
manager.set_data_location()
```

**Return**: None

### **set\_license\_file\_name**

Set licensefile name

**Parameters**:

- **name** (str): license file name

```python
manager = LicenseManager(conf)
manager.set_license_file_name()
```

**Return**: None

### is\_online

Checks if the licensing server is accessible.&#x20;

**Parameters:**

- **throw\_e:&#x20;**(bool,optional): If True throws exception, otherwise exception won't be raised. &#x20;

```python
manager = LicenseManager(conf)

license = manager.is_online()                   
```

**Returns:** **True&#x20;**&#x69;f online, **False&#x20;**&#x6F;therwise.

### create\_offline\_activation\_file

Creates request file for **offline activation**.

**Parameters:**

- **license\_id**(LicenseID):
- **req\_path**(str): path where .req file is created

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H94R-S6KB-L7AJ-SXLK")

req_file_path = manager.create_offline_activation_file(license_id,'offline_files/test')
                                
```

**Returns**(str): path to request file&#x20;

### activate\_license\_offline

Activates the .lic file

**Parameters:**

- **ls\_activation\_path**(str): path to .lic file&#x20;

```python
manager = LicenseManager(conf)

license = manager.activate_license_offline('path_to_lic_file/ls_activation.lic')
                                
```

**Raises:**

- **LicenseActivationException**: Activation data is not valid
- **LicenseActivationException**: Response file ID mismatch
- **LicenseActivationException**: License does not belong to this device

**Returns&#x20;**(License): License object&#x20;

### **get\_air\_gap\_activation\_code**

Get activation code for air gap license

**Parameters**:

- **initialization\_code** (str): initialization code
- **license\_key** (str): license key

```python
initialization_code = "Q/MWfwp1NWAYARl8Q7KSo5Cg2YKqS2QLlnQ3nEeSBsk="
license_key = "UFF3-E9GA-VUJQ-GMLK"

manager = LicenseManager(conf)
activation_code = manager.get_air_gap_activation_code(initialization_code=initialization_code, license_key=license_key)

print("Activation code:",activation_code)
```

**Return&#x20;**(str): activation code

### **activate\_air\_gap\_license**

Activates air gap license

**Parameters**:

- **confirmation\_code** (str): confirmation code
- **policy\_path** (str): policy path (file or folder)
- **license\_key** (str): license\_key
- **policy\_id** (str): policy id

```python
confirmation = "ERbQBuE8giIjqMPj972Skipehqn0szQ8TH56INyo3OdtMHO1SuTVsoCOSnJWB6rml98PJ6SjybTPymOVZTG4hQ=="
policy_id = "998"
license_key = "UFF3-E9GA-VUJQ-GMLK"
policy_path = "path_to_air_lic"

manager = LicenseManager(conf)
license = manager.activate_air_gap_license(
                confirmation_code=confirmation, policy_path=policy_path, license_key=license_key, policy_id=policy_id
            )
```

**Raises**:

- **LicenseActivationException**: Signature verification failed

**Return** (License): License

### **get\_trial\_license**

Creates LiceseID for trial licenses

**Parameters:**

- **customer&#x20;**(Customer)**:&#x20;**&#x43;ustomer object
- **license\_policy**(str,optional): icense policy code. Defaults to None.

```python
customer = Customer(email='python_policy@gmail.com')  

manager = LicenseManager(conf)

license_id = manager.get_trial_license(customer=customer,license_policy='test')
    
license = manager.activate_license(license_id=license_id)
```

**Return**(LicenseID): Returns a LicenseID object.

### **get\_version\_list**

Get versions

**Parameters:**

- **license\_id** (LicenseID): license id object
- **bundle\_code** (str,optional): specify unique bundle\_code of a bundle
- **unique\_license\_id** (int,optional): A unique identifier for the license.
- **env** (str,optional): Version of environment

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("3ZG2-K25B-76VN-WXLK")

response = manager.get_version_list(license_id=license_id)
```

**Return**(list): List of versions

### **get\_installation\_file**

Get installation file

**Parameters**:

- **license\_id** (LicenseID): An instance containing the license key or user credentials
- **bundle\_code** (str, optional): specify unique bundle\_code of a bundle
- **unique\_license\_id** (int, optional): A unique identifier for the license.
- **env** (str, optional): Version of environment
- **version** (str, optional): Versions

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("3ZG2-K25B-76VN-WXLK")

response = manager.get_installation_file(license_id=license_id)
```

**Return** (dict): installation file

### **get\_customer\_license\_users**

Get customer license users

**Parameters**:

- **customer** (Customer): customer

```python
manager = LicenseManager(conf)

customer = Customer(email="c1@c.com")

response = manager.get_customer_license_users(customer=customer)
```

**Return**(dict): customer license user

### **get\_user\_licenses**

Get user licenses

**Parameters**:

- **license\_id** (LicenseID): license\_id

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_user(username="t@tt.com", password="d#2!17vi")

response = manager.get_user_licenses(license_id)
```

**Return**(list): User licenses

### get\_sso\_url

**Parameters**:

- **account\_code** (str): account code
- **use\_auth\_code** (bool, optional): Use code for response\_type. Defaults to True.

```python
manager = LicenseManager(conf)

response = manager.get_sso_url(account_code="your_account_code")
```

**Return**(dict): url

### g**et\_product\_details**

**Parameters**:

- **include\_latest\_version** (bool, optional): include\_latest\_version. Defaults to False.
- **include\_custom\_fields** (bool, optional): include\_custom\_fields. Defaults to False.
- **env** (str, optional): env. Defaults to None.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("3ZG2-K25B-76VN-WXLK")

response = manager.get_product_details(license_id=license_id)
```

**Return**(dict): Product details

## Bundle Manager

object responsible for Bundle operations

```python
from licensespring.licensefile.config import Configuration
from licensespring.licensefile.license_manager import LicenseID
from licensespring.licensefile.bundle_manager import BundleManager

conf = Configuration(
        product="your-product-code",
        api_key="your-api-key",
        shared_key="your-shared-key",
        file_key="d66db34b03c2d6961bb3e14ff40592c0c39ec7210113f194c0da50c2d4d002be",
        file_iv="a770af52b2aa3b73ad218b6cfc4e9707")

bundle_manager = BundleManager(conf)
```

### **activate\_bundle**

Activates the bundle

**Parameters**:

- **license\_id** (LicenseID): An instance containing the license key or user credentials.
- **hardware\_id**(str, optional): A unique identifier for the hardware.
- **unique\_license\_id** (int, optional): A unique identifier for the license.
- **customer\_account\_code** (str, optional): An account code for the customer.
- **id\_token** (str, optional): Token for identity verification.
- **code** (str, optional): An additional code for license verification.
- **app\_ver** (str, optional): The version of the application requesting activation.
- **os\_ver** (str, optional): The operating system version of the host.
- **hostnam**e (str, optional): The hostname of the device requesting activation.
- **ip** (str, optional): The IP address of the device.
- **is\_vm** (bool, optional): Indicates whether the application is running on a virtual machine.
- **vm\_info** (str, optional): Information about the virtual machine, if applicable.
- **mac\_address** (str, optional): The MAC address of the device.

```python
#user based
license_id = LicenseID().from_user(username="ki@ki.com",password="!f53n!z2")
#key based
license_id = LicenseID().from_key("ASQU-AYHA-FX4S-FRLK")

bundles = bundle_manager.activate_bundle(license_id)
```

**Return (dict\[str, License])**: A dictionary where the keys are product short codes and the values are License objects.

### **get\_current\_bundle**

Get current bundle from cache or licensefile.

```python
bundles = bundle_manager.get_current_bundle()
```

**Return (dict\[str, License])**: A dictionary where the keys are product short codes and the values are License objects.

### **create\_offline\_activation\_file**

Creates .req file for activation

**Parameters**:

- **license\_id** (LicenseID): An instance containing the license key or user credentials.
- **req\_path** (str): Specify place where to create .req file
- **hardware\_id** (str, optional): A unique identifier for the hardware.
- **app\_ver** (str, optional): The version of the application requesting activation.
- **os\_ver** (str, optional): The operating system version of the host.
- **hostname** (str, optional): The hostname of the device requesting activation.
- **ip** (str, optional): The IP address of the device.
- **is\_vm** (bool, optional): Indicates whether the application is running on a virtual machine.
- **vm\_info** (str, optional): Information about the virtual machine.
- **mac\_address** (str, optional): The MAC address of the device.
- **device\_variables** (dict, optional): device varaibles.

```python
license_id = LicenseID.from_key("VNFT-7KPY-D5BQ-5NLK")
    
req_file_path = bundle_manager.create_offline_activation_file(license_id, "file_path")
```

**Return(str)**: path of the .req file

### **activate\_bundle\_offline**

Activate offline bundle licenses

**Parameters**:

- **ls\_activation\_path** (str): path to a .lic file

```python
bundle_manager.activate_bundle_offline("file_path_to_lic_file.lic")
```

**Return (dict\[str, License])**: dictionary of licenses in a bundle

### **deactivate\_bundle\_offline**

Generates .req file for the offline deactivation

**Parameters**:&#x20;

- **license\_id** (LicenseID): license\_id&#x20;
- **offline\_path** (str): path of the .req file&#x20;
- **unique\_license\_id** (int): unique license id

```python
license_id = LicenseID.from_key("VNFT-7KPY-D5BQ-5NLK")
file_path = bundle_manager.deactivate_bundle_offline(license_id,"file_path")
```

**Return(str)**: path of the deactivation file

### **check\_bundle**

Check bundle and update the licensefile

**Parameters**:

- **license\_id** (LicenseID): license\_id
- **hardware\_id**(str, optional): A unique identifier for the hardware. Defaults to None.
- **unique\_license\_id** (int, optional): A unique identifier for the license. Defaults to None.
- **include\_expired\_features** (bool, optional): If True, includes expired license features in the check. Defaults to False.
- **env** (str, optional): optional param takes "win", "win32", "win64", "mac", "linux", "linux32" or "linux64". Defaults to None.

```python
license_id = LicenseID.from_key("VNFT-7KPY-D5BQ-5NLK")
# make sure that bundle is activated
bundles = bundle_manager.check_bundle(license_id,"file_path")
```

**Returns (dict\[str, License])**: A dictionary where the keys are product short codes and the values are License objects.

### **deactivate\_bundle**

Deactivate bundle

**Parameters**:

- **license\_id** (LicenseID): license\_id
- **hardware\_id** (str, optional): hardware id. Defaults to None.
- **unique\_license\_id** (int, optional): A unique identifier for the license. Defaults to None.
- **remove\_local\_data** (bool, optional): remove licensefile from storage. Defaults to False.

```python
license_id = LicenseID.from_key("VNFT-7KPY-D5BQ-5NLK")

bundle_manager.deactivate_bundle(license_id,"file_path")
```

## License

Object responsible for license operations

### Methods

### Getters

All getters which are reading the license fields from a local licensefile

```python
# Floating 
license.is_floating_expired() # Determines wheter the license floating period has expired
license.floating_timeout() # License floating timeout
license.is_floating() # True if license if floating, otherwise False
license.floating_client_id() # Floating client id 
license.is_controlled_by_floating_server() # Check if license is controlled by Floating Server 
license.floating_in_use_devices() # Number of floating devices in use 
license.floating_end_date() # Datetime when device will be released
license.max_floating_users() # Number of max floating users
license.expiry_date() # Get the expiry date of a floating license
license.borrow_until() # Get the date until a license is borrwed
license.is_borrowed() # Check if a license is borrowed

# time-limited
license.is_validity_period_expired() # Determines whether the license's validity period has expired
license.validity_period() # Gets the license validity period in UTC
license.validity_with_grace_period() # Gets the validity period with grace period of the license in UTC
license.days_remaining() # Gets how many days are left until the validity period ends
license.is_expired() # Checks if a license validity has expired

# consumption
license.local_consumptions() # Get local consumptions
license.max_consumptions() # Get max consumptions
license.total_consumptions() # Get total consumptions
license.max_overages() # Get max overages
license.allow_unlimited_consumptions() # Check if unlimited consumptions are allowed
license.consumption_reset() # Check if there is consumption reset
license.allow_overages() # Check if overages are allowed

# subscription 
license.allow_grace_subscription_period() # Check if grace subscription period is allowed
license.is_subscription_grace_period_started() # Check if grace subscription period has started
license.get_grace_period() # Get grace period
license.subscription_grace_period() # Get subscription grace period

# all 
 license.license_user() # Gets the license user
 license.is_grace_period_started() # Checks if grace period has started
 license.grace_period_hours_remaining() # Get remain hours of grace period
 license.maintenance_days_remaining() # Gets how many days are left until the maintenance ends
 license.customer_information() # Gets customer information
 license.id() # Gets a license id
 license.max_transfers() # Get a license max transfers
 license.transfer_count() # Get the transfer count
 license.is_device_transfer_allowed() # Get if a device transfer is allowed
 license.is_device_transfer_limited() # Get if a device transfer is limited
 license.days_since_last_check() # Get how many days passed since the last check
 license.start_date() # Get a license start date in UTC
 license.maintenance_period() # Get a license maintenance period in UTC
 license.is_maintence_period_expired() # Checks if maintence period has expired
 license.last_check() # Get when last check was performed in UTC
 license.activation_date() # Get when activation was performed in UTC
 license.last_usage() # Gets a license last usage in UTC
 license.license_type() # Gets the last license usage
 license.max_activations() # Gets the license max activations
 license.metadata() # Gets the license metadata
 license.allow_unlimited_activations() # Check if unlimited activations are allowed
 license.license_enabled() # Checks if a license is enabled
 license.license_active() # Checks if a license is active
 license.is_valid() # Checks if the license is valid (license is active, enabled and didn't expired)
 license.prevent_vm() # Checks if a license prevents virtual machines
 license.is_trial() # Checks if a license is trial
 license.get_product_details() # Get product details
 license.get_device_variable('device_var') # Get device variable if exists
 
 # features
 license.get_feature_data(feature_code) # Get feature data
 
```

### check\_license\_status

Verifies the current status of the license. It raises exceptions if the license is not enabled, not active, or expired

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)
    
license.check_license_status()

                                
```

**Raises**:

**LicenseStateException**: Raised if the license fails one of the following checks:

- License is **not enabled**.
- License i&#x73;**&#x20;not active**.
- License validity period has **expired**.

**Return:** None

### check

Performs an online check to synchronize the license data with the backend. This includes syncing consumptions for consumption-based licenses.

**Parameters:**

- **include\_expired\_features&#x20;**(bool, optional): Includes expired license features in the check.
- **env** (str, optional): "win", "win32", "win64", "mac", "linux", "linux32" or "linux64"

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)
    
response = license.check()

                                
```

**Raises:**

**ClientError**: Raised if there's an issue with the API client's request, such as invalid credentials or unauthorized access.

**RequestException**: Raised if there's a problem with the request to the licensing server, such as network issues or server unavailability.

**Return** (dict): The updated license cache.

### **deactivate**

Deactivates the license and optionally deletes the local license file.

Parameters:

- **delete\_license** (bool, optional)**:&#x20;**&#x49;&#x66;**&#x20;True,&#x20;**&#x64;eletes the local license file upon deactivation.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)
    
license.deactivate()

                                
```

**Return**: None

### local\_check

This method ensures the integrity and consistency of the licensing information by comparing the data stored in the local license file with the predefined configurations in the **Configuration&#x20;**&#x6F;bject.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)
    
license.local_check()

                                
```

**Raises:**

**ConfigurationMismatch**: Raised if the product code or hardware ID in the license file does not match the expected values provided in the **Configuration**

**VMIsNotAllowedException**: Raised if the license is used in a VM environment when the license explicitly disallows it.

**TimeoutExpiredException:&#x20;**&#x52;aised if a floating license has expired. This is more relevant if **is\_floating\_expired&#x20;**&#x69;s later implemented to perform actual checks.

**ClockTamperedException**: Raised if there is evidence of tampering with the system's clock, detected by comparing the system's current time with the last usage time recorded in the license file.

**Return**: None

### **add\_local\_consumption**

Adds local consumption records for consumption-based licenses.

Parameters:

- **consumptions** (int, optional)**:&#x20;**&#x54;he number of consumptions to add locally.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)
    
license.add_local_consumption()

                                
```

**Raises:**

**LicenseSpringTypeError**: Raised if the license type does not support consumption (i.e., not a consumption-based license).

**ConsumptionError**: Raised if adding the specified number of consumptions would exceed the allowed maximum for the license.

**Return:** None

### sync\_consumption

Synchronizes local consumption data with the server, adjusting for overages if specified.

Parameters:

- **req\_overages&#x20;**(int, optional): Specifies behavior for consumption overages.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.add_local_consumption(5)
    
license.sync_consumption()

                                
```

**Raises:**

**RequestException**: Raised if the request to synchronize consumption data with the server fails, for instance, due to network issues or server unavailability.

**Return** (bool): **True** if the consumption data was successfully synchronized; **False** otherwise.

### **is\_grace\_period**

Determines if the current license state is within its grace period following a specific exception.

Parameters:

- **ex&#x20;**(Exception): Raised Exception

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

try:
    license.check()

except Exception as ex
    boolean = license.is_grace_period(ex)    

                    
```

**Return** (bool): **True** if the license is within its grace period, **False** otherwise

### change\_password

Changes password of a user

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_user(username="python@gmail.com",password="7t_x3!o9")

license = manager.activate_license(license_id)

license.change_password("7t_x3!o9","12345678")
    


                                
```

**Return** (str): "password\_changed"

### add\_local\_feature\_consumption

Adds local consumption to the feature.

Parameters:

- **feature** (str): feature code.
- **consumptions** (int,optional): Number of consumptions.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.add_local_feature_consumption("lkprod1cf1",3)                                
```

**Raises:**

**ItemNotFoundError**: If the feature specified by \`feature\_code\` does not exist.

**LicenseSpringTypeError**: If the identified feature is not of the "consumption" type.

**ConsumptionError**: If adding the specified number of consumptions would exceed the feature's consumption limits.

**Return**: None

### sync\_feature\_consumption

Synchronizes local consumption data with the server.

Parameters:

- **feature** (str): feature code.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.add_local_feature_consumption("lkprod1cf1",3)

license.sync_feature_consumption("lkprod1cf1")
                                
```

**Raises:**

**RequestException**: Raised if the request to synchronize consumption data with the server fails, for instance, due to network issues or server unavailability.

**Return** (bool): **True** if the consumption data was successfully synchronized; **False** otherwise.

### floating\_borrow

Attempts to borrow a floating license until the specified date.

Parameters:

- **borrow\_until**(str): A string representing the date until which the license should be borrowed.
- **password** (str, optional): password.&#x20;
- **id\_token** (str, optional): id\_token
- **code** (str, optional): code
- **customer\_account\_code** (str, optional): customer account code.



```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.floating_borrow("2031-05-06T00:00:00Z")

                                
```

**Return**: None

### floating\_release

Releases a borrowed floating license and updates the license status accordingly.

Parameters:

- **throw\_e**(bool): A boolean indicating whether to raise an exception on failure.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.check()

license.floating_release(False)

                                
```

**Raises:**

**Exception**

**Return**: None

### check\_feature

Checks for a specific license feature and updates the license cache accordingly.

Parameters:

- **feature**(str): feature code.
- **add\_to\_watchdog&#x20;**(bool,optional): A boolean indicating whether to add the feature check to a watchdog routine. Default is False

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.check_feature("lkprod1f1fc1") 

                                
```

**Raises:**

**Exception**

**Return**: None

### **borrow\_feature**

Borrow license feature.

**Parameters**:

- **feature** (str): feature code
- **borrow\_until** (str): borrow until e.g "2029-05-06T00:00:00Z"
- **password**(str, optional): password. Defaults to None.
- **id\_token** (str, optional): id\_token. Defaults to None.
- **code** (str, optional): code. Defaults to None.
- **customer\_account\_code** (str, optional): customer account code. Defaults to None.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.check_feature("lkprod1f1fc1")

license.borrow_feature("lkprod1f1fc1","2029-05-06T00:00:00Z")
```

**Return**: None

### release\_feature

Releases a borrowed license feature and updates the license cache accordingly.

Parameters:

- **feature**(str): feature code.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.check_feature("lkprod1f1fc1")

license.release_feature("lkprod1f1fc1")                      
```

**Raises:**

**Exception**

**Return**: None

### update\_offline

Updates license via refresh file

Parameters:

- **path** (str): path of the refresh file
- **reset\_consumption** (bool): True resets consumption otherwise False

```python
file_path = 'path_to_lic_file/license.lic'

manager = create_manager(product="lkprod1",is_guard_file_enabled=True)

license = manager.activate_license_offline(file_path)

license.update_offline('offline_files/license_refresh.lic',False)                   
```

**Raises:**

- **ConfigurationMismatch**: The update file does not belong to this device
- **ConfigurationMismatch**: The update file does not belong to this product

**Return** (bool): True if license was successfully updated otherwise False

### deactivate\_offline

Generates .req file for the offline deactivation

Parameters:

- **offline\_path&#x20;**(str): path of the .req file
- **device\_variables&#x20;**(dict): device variables

```python
file_path = 'path_to_lic_file/license.lic'

manager = create_manager(product="lkprod1",is_guard_file_enabled=True)

license = manager.activate_license_offline(file_path)

license.deactivate_offline('path_where_to_create_req_file')

                                
```

**Return** (str): path of the deactivation file

### **get\_deactivation\_code**

Get deactivation code for air gap licenses

**Parameters**:

- **initialization\_code** (str): initialization\_code

```python
initialization_code="your_initialization_code"
manager = LicenseManager(conf)
#load air gap license
license = manager.load_license()

deactivation_code = license.get_deactivation_code(initialization_code)

print("Deactivation code:",deactivation_code)
                                
```

**Return** (str): deactivation code

### **deactivate\_air\_gap**

Deactivate air gap license and clear storage

**Parameters**:

- **confirmation\_code** (str): confirmation\_code

```python
confirmation_code="your_confirmation_code"
manager = LicenseManager(conf)
#load air gap license
license = manager.load_license()
license.deactivate_air_gap(confirmation_code)
                                
```

**Raises**:

- **LicenseActivationException**: VerificationError

**Return**: None

### **product\_details**

Update product details from LicenseSpring server

Parameters:

- **include\_custom\_fields**(bool, optional): custom fields information. Defaults to False.
- **include\_latest\_version**(bool, optional): Lateset version information. Defaults to False.
- **env** (str, optional): "win", "win32", "win64", "mac", "linux", "linux32" or "linux64"

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H9V3-72XX-ZRAJ-S6LK")

license = manager.activate_license(license_id)
    
response = license.product_details() 
```

**Return**(dict): response

### **set\_device\_variables**

Set device variables locally

Parameters:

- **variables**(dict): variables dict
- **save**(bool, optional): Save cache to licensefile. Defaults to True.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H9V3-72XX-ZRAJ-S6LK")

license = manager.activate_license(license_id)
    
license.set_device_variables({"english":"value"}) 
```

**Return**: None

### **get\_device\_variables**

Get device variables from server or locally

Parameters:

- **get\_from\_be**(bool, optional): If True collects data from LicenseSpring server. Defaults to True.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H9V3-72XX-ZRAJ-S6LK")

license = manager.activate_license(license_id)
    
device_var_list = license.get_device_variables(get_from_be=True)  

print(device_var_list)
```

**Return**(list): List of device variables

### **send\_device\_variables**

Send device variables to LicenseSpring server. Handles GracePeriod

Parameters:

- **variables**(dict): variables dict
- **save**(bool, optional): Save cache to licensefile. Defaults to True.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H9V3-72XX-ZRAJ-S6LK")

license = manager.activate_license(license_id)
    
license.send_device_variables() 
```

**Return**(bool): True if new variables are sent to LicenseSpring server otherwise, False

### custom\_fields

Get custom fields from licensefile

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H9V3-72XX-ZRAJ-S6LK")

license = manager.activate_license(license_id)
    
response = license.custom_fields()
```

**Return**(list): Custom fields

[title] Events API
[path] /

The Events API service is designed to offer a seamless and efficient way to track and respond to a variety of actions and changes occurring within our system. Whether it's a new customer, order or license creation, license expiration etc., our API dispatches events in real-time. These events are the backbone for powering webhooks, enabling external systems and applications to react promptly and automate workflows based on these events.

This service is aimed at developers and system integrators who need to automate reactions to changes within our system. Whether you're looking to enhance user engagement, automate internal processes, or integrate our system with external applications, our Events API provides the necessary tools to achieve these goals efficiently.

[title] Consumption-Based
[path] SDKs/Tutorials/Licensing Scenarios/License Types/

Consumption licenses are ideal for applications where **usage is metered** based on a chosen metric, for example the number of API calls, data transfer volume, or any other measurable unit.&#x20;

These licenses allow developers to set usage limits and track consumption, ensuring fair and flexible licensing for their users.

## Prerequisites

1. Completed the [**Getting Started**](docId\:LSFY9tQ3vfq4ROOW9sHkd) Tutorial, including:
   - Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
   - Created a `LicenseID` using either `LicenseID::fromKey` or `LicenseID::fromUser` function, depending on the activation method you prefer.
   - Activated a license of any type.

## Implementing a Consumption License



![Configuring a Consumption License](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/OBh98Vw2wm43FWjw7JEbJ_image.png "Configuring a Consumption License")

When granting a license, choose the "consumption" type as the preferred option. The key parameters associated with this type are as follows:

1. **Max Consumption:&#x20;**&#x54;his parameter specifies the upper limit for the license usage, defining the maximum number of permitted uses.
2. **Allow Overages:** By using this parameter, the software vendor can determine whether to block any additional usage beyond the maximum consumption limit. This can be further configured to allow a limited number of over usages or to have no restrictions (unlimited) on overages.
3. **Reset Consumption:** This parameter facilitates periodic resetting of the available usage count back to the value provided in the "Max Consumption" field. The reset period can be set to daily, weekly, monthly, or annually, as per the vendor's requirements.

### Obtaining Maximum and Total Consumption

`maxConsumption()` defines the upper limit or cap on the license usage, indicating the maximum number of allowed usages for the licensed product or service. This parameter ensures that users do not exceed a predetermined threshold, enabling software vendors to control and manage the license's usage scope. This method is shown below:

:::CodeblockTabs
```cpp
int32_t LicenseSpring::License::maxConsumption()	
```

```swift
license.maxComsumptions
```

```csharp
int License.MaxConsumption();
```

```python
license.max_consumptions()
```

```java
int maxConsumptions = license.getMaxConsumptions();
```
:::

On the other hand, `totalConsumption()` refers to the actual number of times the license has been utilized by the end-users. Monitoring the total consumption is crucial for both software vendors and users, as it provides insights into the software's popularity and usage patterns.&#x20;

:::CodeblockTabs
```cpp
int32_t LicenseSpring::License::totalConsumption()
```

```swift
license.consumptions
```

```csharp
int License.TotalConsumption();
```

```python
license.total_consumptions()
```

```java
int totalConsumptions = license.getTotalConsumptions();
```
:::

### Adding and Synchronizing Consumption

The function named `updateConsumption()`, shown below, serves to modify the license consumptions based on the value specified in the first parameter.&#x20;

:::CodeblockTabs
```cpp
void LicenseSpring::License::updateConsumption( int32_t value = 1,
bool saveLicense = true )		
```

```swift
try license.updateConsumptions(difference: 3)
```

```csharp
void License.UpdateConsumption(int value = 1);
```

```python
license.add_local_consumption(3)
```

```java
// increase consumption by 5
license.increaseConsumption(5);

// increase consumption by 1
license.increaseConsumption();
```
:::

By default, the value is set to 1, but it can be increased or decreased as needed.&#x20;

Additionally, the function allows users to control whether the updated license information should be saved to a file or not, depending on the `saveLicense` boolean parameter.&#x20;

If `saveLicense` is set to true, the changes will be saved to a file, ensuring persistent license data.

:::hint{type="danger"}
**NotEnoughConsumptionException:&#x20;**&#x54;he consumption license or feature has depleted its available resources.
:::

Seen below, the `syncConsumption()` function is responsible for synchronizing the consumption license values with the server.&#x20;

:::CodeblockTabs
```cpp
void LicenseSpring::License::syncConsumption( int32_t requestOverage = -1 )	

```

```swift
try license.syncConsumptions()
```

```csharp
bool License.SyncConsumption(OverageRequest overageRequest = null);
```

```python
license.sync_consumption()
```

```java
license.syncConsumptions();
```
:::

This synchronization guarantees that the server is up-to-date with the latest accurate consumption-based data.&#x20;

The function accepts an optional parameter, `requestOverage`, which allows users to request consumption overages if necessary.&#x20;

If no specific overage value is provided, the function **will not request** any particular overage amount from the server during synchronization.

### Unlimited Consumption

In an unlimited consumption model, users are granted access to the software with unrestricted usage rights.&#x20;

There are no predefined limits or quotas on the number of times the software can be used or the features that can be accessed.&#x20;

Users can utilize the software freely and continuously, without any concerns about overages or exceeding usage limits.&#x20;

Whether this is enabled can be checked within the SDK by using the following Boolean method:

:::CodeblockTabs
```cpp
bool LicenseSpring::License::isUnlimitedConsumptionAllowed()
```

```swift
license.allowUnlimitedConsumptions
```

```csharp
bool License.IsUnlimitedConsumptionAllowed();
```

```python
license.allow_unlimited_consumptions()
```

```java
LicenseData data = license.getData();
boolean allowUnlimitedConsumptions = data.getAllowUnlimitedConsumptions();
```
:::

## Consumption Overages

In a consumption license, an overage refers to the additional usage beyond the predefined limits or allocated resources set in the license agreement.

Max overages refers to the maximum allowable number of additional usages beyond the defined consumption limit in a given period. Max overages can be accessed by using:

:::CodeblockTabs
```cpp
int32_t LicenseSpring::License::maxOverages()
```

```swift
license.maxConsumptionOverage
```

```csharp
int License.MaxConsumptionOverage();
```

```python
license.max_overages()
```

```java
LicenseData data = license.getData();
int maxOverages = data.getMaxOverages();
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x49;n the case of unlimited overages, `maxOverages()` returns the maximum possible value.
:::

In addition, developers have the option to verify whether overages are permitted by utilizing:

:::CodeblockTabs
```cpp
bool LicenseSpring::License::isOveragesAllowed()
```

```swift
license.isConsumptionOverageAllowed
```

```csharp
bool License.IsConsumptionOverageAllowed();
```

```python
license.allow_overages()
```

```java
LicenseData data = license.getData();
boolean allowOverages = data.isAllowOverages();
```
:::

### Consumption Reset and Period Management

Consumption licenses can be reset on regular intervals, whether it be daily, weekly, monthly, or annually, as per the vendor's requirements. This consumption reset sets the `totalConsumption()` to equal 0, as to reset the total consumptions.

The period of time after which the consumption is reset can be accessed, in the form of a `ConsumptionPeriod` object using the following method:

:::CodeblockTabs
```cpp
 ConsumptionPeriod LicenseSpring::License::consumptionPeriod()	
```

```swift
license.consumptionPeriod
```

```csharp
ConsumptionPeriod License.ConsumptionPeriod();
```

```python
license.consumption_period()
```

```java
LicenseData data = license.getData();
ConsumptionPeriod consumptionPeriod = data.getConsumptionPeriod();
```
:::

Developers can also check for whether this periodic reset is enabled, by using the `isResetConsumptionEnabled()` method on a `License` object:

:::CodeblockTabs
```cpp
bool LicenseSpring::License::isResetConsumptionEnabled()
```

```swift
license.isResetConsumptionEnabled
```

```csharp
bool License.IsConsumptionResetEnabled();
```

```python
license.consumption_reset()
```

```java
LicenseData data = license.getData();
boolean resetConsumption = data.getResetConsumption();
```
:::




[title] C++ SDK Configuration and Usage
[path] SDKs/Tutorials/Getting Started/C++/

C++ SDK allows implementing licensing in two ways:
\- using the **License&#x20;**&#x61;nd **LicenseManager&#x20;**&#x63;lasses;
\- using the **LicenseHandler&#x20;**&#x63;lass.

**LicenseHandler&#x20;**&#x65;ncapsulates **License&#x20;**&#x61;nd **LicenseManager&#x20;**&#x66;unctionality. By default, it is exceptions-free, but you can enable exceptions. It's up to you whether to use **LicenseManager&#x20;**&#x61;nd **License&#x20;**&#x64;irectly or use this class.

**LicenseHandler&#x20;**&#x69;s also useful for Unreal Engine clients because it is free of memory access violation problems due to runtime conflicts with UE.

This article has code samples for both approaches. In the other ones, we will demonstrate  SDK usage only with **LicenseManager&#x20;**&#x61;nd **License**. **LicenseHandler&#x20;**&#x63;lass has methods corresponding to **License**/**LicenseManager&#x20;**&#x66;unctionality.&#x20;

See also our [**Error Handling**](docId:_0Tnmm6ShDrCmLpx4TuOO) tutorial.

## Configuration

To initialize the SDK you will need to fill in your application name and version, product code, and LicenseSpring authentication credentials:

- API and shared key, or
- OAuth client\_id and client\_secret.

:::hint{type="info"}
OAuth support was added in v7.35.0 of the SDK. See [**OAuth Authorization**](docId\:xhYZAUaL9QY4jerxKilmk) on how to set up OAuth.
:::

:::hint{type="info"}
Refer to our [**Hardware ID generation**](docId\:yFnuCniXYZAno8e-sY5I1) on how to pick the best hardware ID generation algorithm for your program.
:::

All credentials can be found can be found on your LicenseSpring account under `Settings->Keys`:

![API and Shared Key Location](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/E8UhHrENKuF-RQw50B4nn_screenshotkeys.png "API and Shared Key Location")

Your product code is located in your product list under Configure Products:

![Product CoProduct Code Location Location](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/LGlB_ERjJM0YF_0EHtMt2_screenshotproduct.png "Product Code Location")

Please, keep in mind that the product code field is case-sensitive.&#x20;

When you have the necessary values, create the configuration.

```cpp
std::string AppName = "My LicenseSpring Application";
std::string AppVersion = "1.0.0";
// use in case of standard authentication
std::string ApiKey = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
std::string SharedKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
// use in case of OAuth authentication
std::string ClientId = "xxxxxx-xxxxx-yyy";
std::string ClientSecret = "ssssssssssssssssssssssssssssss";

std::string ProductCode = "XX";

auto configuration = LicenseSpring::Configuration::Create( ApiKey, SharedKey, ProductCode, AppName, AppVersion );

// or
// setting CryptoProvider key is necessary when using OAuth
// configuration->getCryptoProvider->setKey("password for license encryption key generation");
// auto configuration = LicenseSpring::Configuration::CreateOAuth( ClientId, ClientSecret, ProductCode, AppName, AppVersion );
```

Now you can initialize **LicenseManager** or **LicenseHandler** using this configuration object.

:::CodeblockTabs
LicenseManager

```cpp
auto licenseManager = LicenseManager::create( configuration );
```

LicenseHandler

```cpp
auto& licenseHandler = LicenseHandler::instance();
licenseHandler.reconfigure( configuration );
```
:::

## License Activation

The license keys are located in Licenses section:

![License Key Location](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/xUdyMD7vPArcHnhvLlQxY_screenshotlicense.png "License Key Location")

To implement user-based licensing please refer to: [**User-Based Licensing**](docId\:xEPx04M3OH_F6s8ylf6mZ).

To activate a license, create a **LicenseID** using the given key and call activation method.

:::CodeblockTabs
LicenseManager

```cpp
 auto licenseId = LicenseID::fromKey( "XXXX-XXXX-XXXX-XXXX" );
 auto license = licenseManager->activateLicense( licenseId );
```

LicenseHandler

```cpp
auto& licenseHandler = LicenseHandler::instance();
auto licenseId = LicenseID::fromKey( "XXXX-XXXX-XXXX-XXXX" );
licenseHandler.activateLicense( licenseId );
```
:::

The process of activating a license refers to binding a device to a license. On the LicenseSpring platform, activating the license increments the total activations counter within the license.

:::hint{type="info"}
**SSOException&#x20;**&#x77;ith the message **"Customer account code is not set."** can occur due to incorrect use of the **activateLicense&#x20;**&#x66;unction. This function has two overloads. For a regular license activation, it takes only **LicenseID**. The overload that takes strings is used for SSO. For more information, see [**Single Sign-On**](docId\:FWGT-4DZ4zIEWEl1Nosxq).
:::

## Local License

The local license is a copy of the license information that is saved on the end user's local computer. Users who have not activated the license on their end before will not have a local license. By default, the local license is stored: `%USERPROFILE%\AppData\Local\LicenseSpring\”Product Code”\License.key`.

See [**Local License File**](docId\:FkfZHhA-N838tZNrZu0sZ) for more information.

If a device already has a license, and you try to activate another license on that device, for the same product, that newly activated license will override the existing license, deleting it from the device. This will be on the developer to make sure that they check if a license exists on the device before a new activation:

:::CodeblockTabs
LicenseManager

```cpp
auto license = licenseManager->getCurrentLicense();
if( license == nullptr )
    //activate a new license
```

LicenseHandler

```cpp
auto& licenseHandler = LicenseHandler::instance();
if( !licenseHandler.isLicenseExists() )
    //activate a new license
```
:::

## License Check

It is recommended to perform a local license check at application start to confirm that the local license file belongs to the current device and has not been transferred.&#x20;

It is also useful to check whether the local license file has been tampered with and whether the local license is still valid.&#x20;

An additional check verifies the license signature returned by the License API on license activation or check. If the license was tampered with, the local check will throw an exception if the `verifySignature` parameter is set to `true`.

:::hint{type="danger"}
If the license was activated with C++ SDK v7.32.0 or earlier, local check with signature verification will throw an exception because the local license state doesn't contain the signature signed by the LicenseSpring backend.

In that case, users must first either do an offline license update, or an online license check. This only needs to be done once.&#x20;
:::

:::CodeblockTabs
License

```cpp
bool verifySignature = false; // also false by default
license->localCheck( verifySignature );
//throws exceptions in case of errors
```

LicenseHandler

```cpp
auto& licenseHandler = LicenseHandler::instance();
licenseHandler.checkLicenseLocal();
if( licenseHandler.wasError() )
    //handle errors
    LSErrorCode error = lh.getLastError();
else
    //license check is successful
```
:::

The local check can produce the following errors:

| Exception                         | Error code                                                        | Reason                                                     |
| --------------------------------- | ----------------------------------------------------------------- | ---------------------------------------------------------- |
| `LicenseStateException`           | `eLicenseDisabled`<br />`eLicenseInactive`<br />`eLicenseExpired` | License is in invalid state (disabled, epired or inactive) |
| `ProductMismatchException`        | `eProductMismatchError`                                           | License does not belong to configured product              |
| `DeviceNotLicensedException`      | `eDeviceError`                                                    | License does not belong to current device                  |
| `ClockTamperedException`          | `eClockTamperedError`                                             | Detected cheating with system clock                        |
| `FloatingTimeoutExpiredException` | `eFloatingTimeoutExpired`                                         | Timeout for floating license has expired                   |
| `VMIsNotAllowedException`         | `eVMNotAllowed`                                                   | VM was detected while VM check is turned on                |
| `SignatureMismatchException`      | `eSignatureMismatchError`                                         | Local license signature has been tampered with.            |

Online license check refreshes the local license with the data from LicenseSpring backend:

:::CodeblockTabs
License

```cpp
license->check();
//throws exceptions in case of errors
```

LicenseHandler

```cpp
auto& licenseHandler = LicenseHandler::instance();
licenseHandler.checkLicense();
if( licenseHandler.wasError() )
    //handle errors
    LSErrorCode error = lh.getLastError();
else
    //license check is successful
```
:::

The online check can produce the following errors:

| Exception                                                                          | Error code                                                            | Reason                                                                                                                                                             |
| ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `LicenseStateException`                                                            | `eLicenseDisabled`<br />`eLicenseInactive`<br />`eLicenseExpired`     | License is disabled, was reset or expired                                                                                                                          |
| `DeviceNotLicensedException`<br />`DeviceBlacklistedException`                     | `eDeviceError`<br />`eDeviceBlacklisted`                              | License does not belong to current device or the device was blacklisted                                                                                            |
| `NoInternetException`<br />`NetworkTimeoutException`<br />`LicenseServerException` | `eNoInternetError`<br />`eNetworkTimeoutError`<br />`eServerError`    | Connection-related errors: if there's no Internet or an internal server error occured.                                                                             |
| `MaxFloatingReachedException`                                                      | `eMaxFloatingReached`                                                 | There are no free floating slots for license                                                                                                                       |
| `UnknownLicenseSpringException`                                                    | `eUnknownError`                                                       | Unknown error. Contact support in this case                                                                                                                        |
| `OAuthException`                                                                   | `eUnauthorizedClient`<br />`eOAuthRequired`<br />`eOAuthTokenExpired` | Invalid client credentials.<br />License requires OAuth authentication.<br />OAuth token is expired. This shouldn't happen as the SDK keeps track of its lifetime. |

This method also returns the most recent **InstallationFile** available for the license which can be useful for managing software updates.&#x20;

For more information about managing software updates, see [**Handling Product Versions**](docId\:ZvfCf4-5cQ4UJ4dnsOvBb).

You can also check for active, valid, enabled, and expired licenses using `isActive`, `isValid`, `isEnabled`, and `isExpired` methods respectively.&#x20;

Note that an active license does not necessarily mean a license is valid. A valid license means the license is active, enabled, and not expired. An active license means that the license is bound to a device, but may also be disabled or expired.

## Full Code Sample

Below you can find a code sample that initializes the SDK, retrieves a local license or activates a new one, and performs the necessary checks.

:::CodeblockTabs
LicenseManager

```cpp
std::string AppName = "My LicenseSpring Application";
std::string AppVersion = "1.0.0";
// use in case of standard authentication
std::string ApiKey = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
std::string SharedKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
// use in calse of OAuth authentication
std::string ClientId = "xxxxxx-xxxxx-yyy";
std::string ClientSecret = "ssssssssssssssssssssssssssssss";

std::string ProductCode = "XX";

auto configuration = LicenseSpring::Configuration::Create( ApiKey, SharedKey, ProductCode, AppName, AppVersion );

// or
// setting CryptoProvider key is necessary when using OAuth
// configuration->getCryptoProvider->setKey("password for license encryption key generation");
// auto configuration = LicenseSpring::Configuration::CreateOAuth( ClientId, ClientSecret, ProductCode, AppName, AppVersion );

try
{
    auto licenseManager = LicenseManager::create( configuration );
    auto license = licenseManager->getCurrentLicense();
    if( license == nullptr )
    {
        auto licenseId = LicenseID::fromKey( "XXXX-XXXX-XXXX-XXXX" );
        license = licenseManager->activateLicense( licenseId );
    }
    license->localCheck();
    license->check();
}
catch( const LicenseSpringException& ex )
{
    std::cout << "LicenseSpring exception encountered: " << ex.what();
}
```

LicenseHandler

```cpp
std::string AppName = "My LicenseSpring Application";
std::string AppVersion = "1.0.0";
std::string ApiKey = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
std::string SharedKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
std::string ProductCode = "XX";

auto configuration = LicenseSpring::Configuration::Create( ApiKey, SharedKey, ProductCode, AppName, AppVersion );

auto& licenseHandler = LicenseHandler::instance();
licenseHandler.reconfigure( configuration );
if( !licenseHandler.isLicenseExists() )
{
    auto licenseId = LicenseID::fromKey( "XXXX-XXXX-XXXX-XXXX" );
    licenseHandler.activateLicense( licenseId );
    if( licenseHandler.wasError() )
        std::cout << "LicenseSpring error encountered: " << licenseHandler.getLastErrorMsg();
}

licenseHandler.checkLicenseLocal();
if( licenseHandler.wasError() )
    std::cout << "LicenseSpring error encountered: " << licenseHandler.getLastErrorMsg();

licenseHandler.checkLicense();
if( licenseHandler.wasError() )
    std::cout << "LicenseSpring error encountered: " << licenseHandler.getLastErrorMsg();
```
:::

## License Deactivation

Deactivating a license unbinds the device from the license, and decrements the number of total activations. Depending on the license transfer policy, this usually means that the license is freed up to be activated onto a new device. Deactivating is done using the following method:

:::CodeblockTabs
License

```cpp
if( license->deactivate() )
    std::cout << "License deactivated successfully.";
```

LicenseHandler

```cpp
auto& licenseHandler = LicenseHandler::instance();
if( licenseHandler.deactivateLicense() )
    std::cout << "License deactivated successfully.";
```
:::

The `License::deactivate()` method allows to specify whether you want to remove the local license file after the deactivation. Set the `removeLocalData` parameter to `true` if you want the local files to be removed.

[title] Android support
[path] SDKs/Tutorials/Getting Started/C++/

Since **v7.38.0,** LicenseSpring provides a C++ SDK built using the **Android NDK,** designed for Android applications. The SDK is compatible with Android devices running **Android API Level 24 (Android 7.0 Nougat)** or higher.

- **NDK Version**: 26.1.10909125 and 27.2.12479018
- **Minimum Android API Level**: 24 (Android 7.0 Nougat)
- **ABI version**: arm64-v8

The SDK provides native C++ functionality and is optimized for performance on supported Android devices.

## JNI initialization

The SDK includes JNI code used for computing the hardware ID of the Android device, and the default data path used for writing the license and log files:

- `Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID)` is used to compute the hardware ID,
- `context.getFilesDir().getAbsolutePath()` is used to compute the default data path.

To set these values and integrate the native LicenseSpring library into your app, we provide a small class that you need to include in your project:



```kotlin
package com.licensespring.android

import android.content.Context
import android.util.Log

object LicenseSpring {

    // This method decalaration exactly matches the signature declared in the LicenseSpring SDK. Don't remove it.
    external fun setAndroidContextAndIDs(context: Context)

    init {
        try {
            System.loadLibrary("LicenseSpring")
            Log.d("LicenseSpring", "Native library loaded successfully")
        } catch (e: UnsatisfiedLinkError) {
            Log.e("LicenseSpring", "Failed to load native library: ${e.message}")
        }
    }

    fun initialize(appContext: Context) {
        try {
            setAndroidContextAndIDs(appContext.applicationContext)
            Log.d("LicenseSpring", "Native context and IDs set successfully")
        } catch (e: Exception) {
            Log.e("LicenseSpring", "Error calling native method: ${e.message}")
        }
    }
}
```

You should include this snippet in your project and call `LicenseSpring.initialize(context)` during your app startup. If you don't want to pass the context to the LicenseSpring C++ SDK, you must set your own [**hardware ID**](https://docs.licensespring.com/sdks/tutorials/best-practices/hardware-id) and [**data path.**](https://docs.licensespring.com/sdks/tutorials/best-practices/local-license-file)

A full example is contained in the `samples/AndroidNDKSample` project, together with a demo Android app where you can activate and check licenses.




[title] Legacy algorithms
[path] SDKs/Tutorials/Best Practices/Hardware ID generation/

Before standardizing the hardware ID algorithms, different LicenseSpring SDKs used to compute slightly different hardware IDs. Each platform that SDKs run on had a default algorithms and alternative algorithms.

## Default Algorithm

1. **Windows:&#x20;**&#x44;efault hardware ID algorithm uses WMI to fetch Model, Manufacturer, Name, SerialNumber of the motherboard, processor and the system disk. Afterwards, it encodes them to provide a unique string that  represents the current device.
2. **Linux:&#x20;**&#x44;efault device id reads the machine id from the `/etc/machine-id` file. This file contains the unique machine ID of the local system that is set during installation or boot. If this id is not found, it tries to read the `/var/lib/dbus/machine-id` file. If it still fails to get the id, it writes a generated UUID.
3. **MacOS:** The C++ SDK uses the `gethostuuid()` system call to get a unique identifier of the device. The .Net SDK gets `IOPlatformUUID` value.  The Swift SDK gets the machine UUID.
4. **iOS**: The Swift SDK gets `UIDevice.current.identifierForVendor` .

## Windows Algorithms

### C++ SDK

1. **Gen2** algorithm is similar to the default algorithm. It is safer and shorter than default. This algorithm retrieves the Manufacturer and SerialNumber of the motherboard, CPU name and id, and disc model and serial number. This algorithm can be useful for air gap licenses.
2. **WinCSProductId** is an alternative algorithm for Windows. It gets the UUID of the Windows machine using Computer System Product Id through WMI.
3. **WinCryptographyId** is an algorithm for Windows that doesn't use WMI. It gets Microsoft Cryptography MachineGuid from Windows registry.

### .Net SDK

1. **Gen1** includes minor improvements for ID calculation on Windows, on other platforms the same as default.
2. **Gen2** and **Gen3** are safer device id algorithms on Windows, on other platforms the same as default. **Gen3** is a shorter form that can be useful for air gap licenses.
3. **WinAlternative** algorithm tries to&#x20;   get Microsoft Cryptography MachineGuid from Windows registry. If this request fails or .Net Framework version is earlier than 4.0, it tries to get the UUID of the Windows machine using Computer System Product Id.

## Cloud Platform Algorithms

1. **CloudPlatformsId** is useful when the software runs on **Azure**, **AWS&#x20;**&#x6F;&#x72;**&#x20;GCP**. It is a good option when the application will be used only on these platforms. If the application can be installed on other platforms as well, the **AutoId** algorithm should be used.
2. **AutoId** uses different approaches depending on your platform. If the application is running on Azure, AWS or GCP, it is the same as **CloudPlatformsId**, otherwise the same as **Default**.
3. **AutoIdWinCloud&#x20;**&#x61;lso uses different platform-dependent approaches. If the application is running on Azure, AWS or GCP, it is the same as **CloudPlatformsId**, otherwise the same as **WinCSProductId**. This algorithm should only be used on Windows computers.

## Hardware ID Usage

### Configuration

After choosing an algorithm, set it in ExtendedOptions or LicenseSpringConfiguration:

:::CodeblockTabs
```cpp
LicenseSpring::ExtendedOptions options;
options.setDeviceIdAlgorithm(AutoId);
```

```csharp
var options = new ExtendedOptions();
options.DeviceIdAlgorithm = DeviceIDAlgorithm.AutoId;
```

```swift
configuration.hardwareID = generateMyOwnCustomID()
```

```java
LicenseSpringConfiguration config = LicenseSpringConfiguration.builder()
  .identityProvider(HardwareIdStrategy.AUTO_HARDWARE_ID)
  .build();
```
:::

The .NET SDK allows to specify the timeout for cloud platforms ID id requests. It is useful when **AutoId** takes too long on a regular machine. This value is specified in milliseconds, the default is 200.

```csharp
options.CloudIdRequestTimeout = 100;
```

The SDK allows overriding hardware ID. For instance, you can use the MAC address as the hardware ID:

:::CodeblockTabs
```cpp
LicenseSpring::ExtendedOptions options;
options.setHardwareID(options.getNetworkInfo().mac());
```

```csharp
var configuration = new LicenseSpring.Configuration();
var options = new LicenseSpring.ExtendedOptions();
options.HardwareID = configuration.MACAddress;
configuration.ExtendedOptions = options;
```

```go
// Go SDK v2
lm_config := license_manager.LicenseManagerBasicConfiguration{
				OAuth:             false,
				ApiKey:            "your-api-key",
				SharedKey:         "your-shared-key",
				ProductCode:       "your-product-code",
				AuthData:          auth.FromKey("LICENSE-KEY"),
			}

lm, _ := license_manager.NewLicenseManager(
    lm_config,
    license_manager.WithHardwareId("your-HW-ID"),
)
```

```java
LicenseSpringConfiguration config = LicenseSpringConfiguration.builder()
  .identityProvider(customIdentityProvider)
  .build();
```
:::

###


[title] C++ SDK Installation
[path] SDKs/Tutorials/Getting Started/C++/

The C/C++ LicenseSpring SDK can be downloaded at: [**C++ SDK**](docId\:vhNphrjIDMgaVkFh7laWx)

## Windows

Windows 7 and later are supported. We provide SDK builds created with

- Visual Studio 2015 - VC140,
- Visual Studio 2017 - VC141,
- Visual Studio 2019 - VC142,
- Visual Studio 2022 - VC143,
- Visual Studio 2025 - VC145,
- MinGW-w64.

## MacOS

We provide libraries for x86\_64 and arm64 architectures, as well as universal binaries that contain both.

The x86\_64 version is built targeting MacOS 10.12, and the arm64 is built targeting MacOS 11.3.

## Linux

You can find a variety of Linux builds and choose the right package for your environment and configuration. We provide builds for different architectures:

- x86\_64,
- arm - with and without hardware floating point support,
- aarch64;

Different compilers:

- GCC 9.2 and GCC 7.5, with and without C++11 ABI (OldABI)
- Clang 11, Clang 14 and Clang 19

## Package Content

![Package Contents](https://lh4.googleusercontent.com/mDL1Xk14WUxizBi9UMZM7yi4Yur2jf5RA0Wr_aIleRzex47o8lQZqL9ubQSFlTib-1DOTKxKwuFk9SgCpcXEfdOr1OLrBInVUt0dWb4chY3bcPYfyNqO0h_AP2SWEgSKUZx7DuNHIMKjleEsahdavg "Package Contents")

After downloading and unzipping the archive, you will find the following items in the **LicenseSpring&#x20;**&#x66;older:

The **bin** folder contains LicenseSpring libraries:

- **On Windows**, there are dynamic and static libraries for x86 and x64 Windows platforms. `bin/dynamic` contains dynamic libraries, `bin/staticMD`contains static libraries linked against the shared runtime library, and `bin/staticMT`contains static libraries linked agains the static runtime library.
- `bin/dynamic` also contains the `LicenseSpringVMD.dll`library used for virtual machine detection.
- Since v7.37.0, we also provide `bin/dynamic_HardwareKey` where `LicenseSpring.dll` links to `libykpiv.dll`
- Since v7.42.0, we also ship `hardware_id_generator.dll` in `bin/dynamic`
- **On Linux**, `bin/shared` contains shared libraries, and `bin/static`contain static libraries.
- Since v7.37.0, we also provide `bin/shared_HardwareKey`, where `libLicenseSpring.so` links to `libykpiv.so`
- Since v7.42.0, we also ship `libhardware_id_generator.so`next to all `libLicenseSpring.so`binaries.
- **On macOS**, `bin/shared` contains shared libraries, and `bin/static`contain static libraries.
- Since v7.37.0, we also provide `bin/shared_HardwareKey`, where `libLicenseSpring.dylib` links to `libykpiv.dylib`
- Since v7.42.0, we also ship `libhardware_id_generator.so`next to all `libLicenseSpring.dylib`binaries.

The **certificates** folder contains a certificate bundle. It is recommended to include the .crt file along with your software. Place the .crt file or certificates folder next to your binary file.

The **documentation** folder contains a full reference of SDK classes.

The **include** folder contains header files of the LicenseSpring library and its dependencies, cURL, and OpenSSL.

The **samples** folder contains several sample projects. Please refer to CppSample or CSample to begin using LicenseSpring. These projects provide basic examples of licensing implementation using the SDK.

![Samples Folder](https://lh6.googleusercontent.com/ToYKwOMfSOd_o0a6VdFkUruS5yeWm8YDHg9GSKF8QJKeG5ZkmYf2RS1gzWnae_oSecyH3DdM3l35MhAJsZgGq2QnR3NSCWOeW1Hs0zdQF_a8oilMmQ2SHDmJOrou1AMe59rmGWJxUWfMvxcKpYzRuw "Samples Folder")

The package also contains the **README, LICENSE, and ReleaseNotes** files.&#x20;

**README** has useful links and information about SDK dependencies and certificates.&#x20;

**LICENSE** contains the **LSSCL license agreement**.

[title] Floating Client
[path] SDKs/Java SDK/Java Modules/

Floating Client is a module that has everything related to floating licenses. See [**Floating Licenses**](docId:4aUNyPIaL8I2te4NypPx7) for more information about floating licenses.

To include Floating Client into your Maven/Gradle project add this snippet:

:::CodeblockTabs
```xml
     <dependencies>
       <dependency>
            <groupId>com.licensespring</groupId>
            <artifactId>licensespring-floating-client</artifactId>
            <version>2.16.1</version>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>jdk-java</id>
            <url>https://licensespring-maven.s3.eu-central-1.amazonaws.com/</url>
        </repository>
    </repositories>
```

```java
repositories {
    mavenLocal()
    maven {
        url = 'https://licensespring-maven.s3.eu-central-1.amazonaws.com/'
    }
}

dependencies {
    implementation 'com.licensespring:licensespring-floating-client:2.16.1'
}
```
:::

*Javadoc, Jar and OSGi bundle downloads can be found at:&#x20;*[**Javadoc & Downloads**](docId\:Dm-Ksn9S-VVHGLpYWSm5x)

## Initializing the Floating Client module

The floating client, as opposed to License Client SDK, is implemented as a service. More than one instance can be created, and the usage template is you need one `FloatingLicenseService` per product that you need to use. For most use cases this is one. This approach enables having multiple products within your application and multiple licenses per `FloatingLicenseService` instance.

The `License` identity needs to be preserved somewhere within your application, as the references to active licenses are not saved within this module.

To initialize the SDK, you must supply authentication credentials and product information. You can choose one of two authentication methods:

**1. API Key Authentication:**

- **apiKey:** Your company API key
- **sharedKey:** A company-specific encryption key used when signing requests

**2. OAuth Authorization:**

- **clientId:** Your client identifier
- **clientSecret:** Your client secret

In addition to the authentication credentials, you must provide the **productCode**, an alphanumeric code identifying the specific product. The `apiKey` and `sharedKey` are available in the LicenseSpring Platform under "Settings -> Settings -> Keys." For [**OAuth Authorization**](docId\:xhYZAUaL9QY4jerxKilmk), your `clientId` and `clientSecret` are available here: [**OAuth Configuration**](docId\:q1YECed3KGhZMwcSX2MOJ) . The `productCode` is defined when creating the product and ties the license to that specific product.

**Optional** Configuration parameters for initializing the Floating Client SDK:

- `addShutdownHook` indicates if you want the SDK to automatically release any currently active licenses on the device before you shut down the runtime process. Default is true.
- `enablePeriodicCheck` enables periodic calls to `checkLicense` method to prolong the license usage. It will be prolonged every time the license has passed half of its floating timeout time. Usage time is set through the LicenseSpring platform with the LicenseSpring platform with the `floatingTimeout` parameter in the product configuration.
- `checkSubscriber` subscriber on periodic check, default implementation is `DoNothingSubscriber`, but you can add your own implementation to handle the `onSuccess` and `onError` of the periodic check. This, of course, isn't a parameter you need to worry about if you chose not to enable periodic checks.
- `requestLogging `request logging for debug purposes, default is no request logging.
- `appName` name of the application using the SDK
- `appVersion` manually set the version of the application that's using the SDK.
- `identityProvider` set a custom `IdentityProvider` which generates unique keys for a particular device. Default implementation for floating is `ONCE_PER_PROCESS`. More details can be found on our [**Java Hardware (Device) IDs**](docId\:KinnDEO4BgHcV3azYvchM) page.
- `cacheHardwareId` set to true to allow caching of hardware iDs. Default is true. You can change this to false if your hardware Id strategy isn't ONCE\_PER\_PROCESS.
- `enableNegativeConsumptions` enables the option to send negative consumptions, default is false.
- `proxyPort`and `proxyHost` used to setup a forward proxy, see more in [**Java Advanced Usage**](docId\:mqLRngvkrEpJ5IVdGUpt0)
- `requestTimeout` set the timeout of requests make to API (in seconds), default is 10 seconds
- `storeMachineInfo`false by default. This toggles the collection of additional machine data, which includes:
  - `hostname`
  - `ipAddress`
  - `macAddress`
  - `vmInfo`
  - `osInfo`
- `infoToStore`- specify what information to store, ignored if `storeMachineInfo` is false, defaults to ALL if left empty.



```java
// initialization with minimum parameters
try {
	FloatingConfiguration configuration = FloatingConfiguration.builder()
                .apiKey("api_key")
                .sharedKey("shared_key")
                .productCode("product_code")
                .build();
} catch (LicenseSpringConfigurationException e) {
    log.error(e.getCause().getMessage());
}

// OAuth minimum parameters
try {
	FloatingConfiguration configuration = FloatingConfiguration.builder()
                .clientId("client_id")
                .clientSecret("client_secret")
                .productCode("product_code")
                .build();
} catch (LicenseSpringConfigurationException e) {
    log.error(e.getCause().getMessage());
}
LicenseSpringConfiguration configuration = LicenseSpringConfiguration.builder()
                        
                        .sharedKey("shared-key")
                        .build();               

// initialization with more parameters
try {
	FloatingConfiguration configuration = FloatingConfiguration.builder()
                .apiKey("api-key")
                .productCode("product-code")
                .sharedKey("shared-key")
                .addShutdownHook(false)
                .requestLogging(Logger.Level.FULL)
                .appName("MyApplication")
                .appVersion("1.0.1")
                .enableNegativeConsumptions(true)
                .requestTimeout(60L)
                .storeMachineInfo(true)
                .infoToStore(InfoToStore.VM_INFO)
                .infoToStore(InfoToStore.HOSTNAME)
                .build();
} catch (LicenseSpringConfigurationException e) {
    log.error(e.getCause().getMessage());
}
```

## FloatingLicenseService

After setting up the SDK, there are a number of methods and objects available to the app developer.

To make the `FloatingLicenseService`, initialize it by passing the `FloatingConfiguration` object you set up earlier.

```java
FloatingLicenseService service = new FloatingLicenseService(configuration);
```

Now you can use the methods that `FloatingLicenseService` provides.

### activateLicense(ActivationLicense identity)

Attempts to activate the product using provided `ActivationLicense`. Returns the `LicenseData` object that has been activated. There are two available factory methods to make the `ActivationLicense` object, the method you need to use depends if your product is license key-based or user-based.

```java
// If your licenses are user based: (note that password is never saved in the sdk)
// ActivationLicense extends the LicenseIdentity class
ActivationLicense identity = ActivationLicense.fromUsername("username", "password");
// If your licenses are key based:
ActivationLicense identity = ActivationLicense.fromKey("license-key");

// Activate the license, the method returns LicenseData object
try {
	LicenseData data = service.activateLicense(identity);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

// This is what LicenseData object looks like, so you can better grasp what fields of the object are at your disposal.
// All fields are read only.
public class LicenseData {
    String licenseSignature;
    LicenseType licenseType;
    boolean isTrial;

    List<LicenseFeature> productFeatures;
    List<CustomField> customFields;

    ZonedDateTime validityPeriod;
    ZonedDateTime maintenancePeriod;

    int totalConsumptions;
    int maxConsumptions;

    int maxActivations;
    int timesActivated;

    Customer customer;

    Product productDetails;

    boolean isFloatingCloud;
    int floatingUsers;
    boolean floatingInUse;
    int floatingTimeout;

    public boolean isExpired();
    public long daysRemaining();
}
```

### checkLicense(LicenseIdentity data)

After you activated the license you can now use the check method to prolong the usage of the license and check its validity, since it expires after floating timeout period has passed (this can be set up in product configuration on the LicenseSpring platform). This method returns `CheckResponse` object that contains `LicenseData`, `InstallationFile` and flags if license is active, enabled or expired.

This method can be called periodically if you leave the `enablePeriodicCheck` true in the `FloatingConfiguration` so you don't have to worry about the floating license expiring while the user is still using it.

```java
// You can use the previous identity to check the license
ActivationLicense identityFromUser = ActivationLicense.fromUsername("username", "password");
ActivationLicense identityFromKey = ActivationLicense.fromKey("license-key");

// or you can make a new LicenseIdentity object that doesn't contain the password
LicenseIdentity identityFromUser = LicenseIdentity.builder()
                .username("username")
                .build();

LicenseIdentity identityFromKey = LicenseIdentity.builder()
                .licenseKey("license-key")
                .build();

try {
	CheckResponse response = service.checkLicense(identityFromUser);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

// CheckResponse object
public class CheckResponse {
    private transient LicenseData data;
    private transient InstallationFile file;

    private boolean licenseActive;
    private boolean licenseEnabled;
    private boolean isExpired;
}
```

### **CheckLicenseSub**scriber

The check subscriber can be added as a custom handler when the check API is called (e.g. in a background thread).

```java
public class MySubscriber implements CheckLicenseSubscriber{
    @Override
    public void onError(LicenseIdentity old, LicenseSpringException exception) {
        // handle the error
    }

    @Override
    public void onSuccess(CheckResponse checkResponse) {
        // the check response recieved
    }
}


// when building the configuration add the instance on the configuration builder

try {
	FloatingConfiguration configuration = FloatingConfiguration.builder()
                .apiKey("api-key")
                .productCode("product-code")
                .sharedKey("shared-key")
                .checkSubscriber(new MySubscriber())
                 .build();
} catch (LicenseSpringConfigurationException e) {
    log.error(e.getCause().getMessage());
}
```

### BorrowedLicenseExpirationSubscriber

The borrowed license expiration subscriber can be added as a custom handler when the borrowed license borrow time expires.

```java
public class MySubscriber implements BorrowedLicenseExpirationSubscriber{
    @Override
    public void onBorrowedLicenseExpiration(LicenseBorrowResponse response) {
        // Your custom handler
    }
}


// when building the configuration add the instance on the configuration builder

try {
	FloatingConfiguration configuration = FloatingConfiguration.builder()
                .apiKey("api-key")
                .productCode("product-code")
                .sharedKey("shared-key")
                .borrowedLicenseExpirationSubscriber(new MySubscriber())
                .build();
} catch (LicenseSpringConfigurationException e) {
    log.error(e.getCause().getMessage());
}
```

### addConsumption(LicenseIdentity identity, int consumptions)

If your license is the `Consumption` type you can increase the consumptions by the parameter provided. This method makes a request to the LicenseSpring server to increase the consumptions on the identity you provided.

```java
// see checkLicense method how you can build identity differently
LicenseIdentity identityFromKey = LicenseIdentity.builder()
                .licenseKey("license-key")
                .build();

// adds one consumption to the provided identity
try {
	service.addConsumption(identity, 1);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

// if enableNegativeConsumptions is set to true in FloatingConfiguration object
// you can add negative consumptions
try {
	service.addConsumption(identity, -1);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}
```

### addFeatureConsumption(LicenseIdentity identity, int consumptions)

If your license is the `Consumption` type and you have certain features in your app that you want to track consumptions for separately, you can increase the consumptions of the feature by the parameter provided. This method makes a request to the LicenseSpring server to increase the feature consumptions on the identity you provided.

```java
// see checkLicense method how you can build identity differently
ActivationLicense identity = ActivationLicense.fromKey("license-key");

// adds one consumption on feature "feature" to the identity provided
try {
	service.addFeatureConsumption(identity, "feature", 1);	
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

// if enableNegativeConsumptions is set to true in FloatingConfiguration object
// you can add negative feature consumptions
try {
	service.addConsumption(identity, "feature", -1);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
```

### installationFile(LicenseIdentity identity

Returns the latest valid installation file, if installation files are defined in the LicenseSpring platform. For more details please see [**Product Versioning**](docId\:sz5ImOvmj5QJaWhELsOXt).

```java
// see checkLicense method how you can build identity differently
ActivationLicense identity = ActivationLicense.fromKey("license-key");

try {
	InstallationFile file = service.installationFile(identity);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}
```

### trackVariables(LicenseIdentity identity, Map\<String, String> variables)

Tracks device based variables for end uses.

```java
// see checkLicense method how you can build identity differently
ActivationLicense identity = ActivationLicense.fromKey("license-key");
// see checkLicense method how you can build identity differently
ActivationLicense identity = ActivationLicense.fromKey("license-key");

Map<String, String> variables = new HashMap<>();
variables.put("var1", "val1");
variables.put("var2", "val2");

try {
	service.trackVariables(identity, variables);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

try {
	InstallationFile file = service.installationFile(identity);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}
```

### versions(LicenseIdentity identity)

Returns an array of strings with all available versions.

```java
// see checkLicense method for more ways to build identity
ActivationLicense identity = ActivationLicense.fromKey("license-key");

try {
	String[] versions = service.versions(LicenseIdentity.fromKey("license-key"));
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}
```

### productDetails()

Gets product details from LicenseSpring servers.

```java
try {
	Product product = service.productDetails();
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

log.info(product.getProductName());
log.info(product.getShortCode());
log.info(product.isAllowTrial());
log.info(product.getTrialDays());
log.info(product.getAuthorizationMethod());

// product class
public class Product {
    private String productName;
    private String shortCode;
    private boolean allowTrial;
    private int trialDays;
    private String authorizationMethod;
}// see checkLicense method for more ways to build identity
ActivationLicense identity = ActivationLicense.fromKey("license-key");

try {
	String[] versions = service.versions(LicenseIdentity.fromKey("license-key"));
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}
```

### releaseLicense(LicenseIdentity identity)

A floating cloud license is released from a current device. You need to supply the license identity. This is done automatically before the process shuts down normally if you leave the `addShutdownHook` property true in the `FloatingConfiguration`. Additionally, the license is also deactivated for the current device.

```java
// see checkLicense method for more ways to build identity
ActivationLicense identity = ActivationLicense.fromKey("license-key");

try {
	service.releaseLicense(identity);
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}
```

### deactivateLicense(LicenseIdentity identity)

A license can be deactivated using this method, then the license can be used on another device. Returns true if deactivation was successful, false if it wasn't.

```java
// see checkLicense method for more ways to build identity
ActivationLicense identity = ActivationLicense.fromKey("license-key");

try {
	if (service.deactivateLicense(identity) {
        System.out.println("License successfully deactivated.");
    } else {
        System.out.println("Something went wrong.");
    }
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

```

### borrowLicense(LicenseIdentity identity)

A license can be borrowed using this method.

```java
// see checkLicense method for more ways to build identity
ActivationLicense identity = ActivationLicense.fromKey("license-key");
try {
  service.borrowLicense(identity, ZonedDateTime.now().plusHours(1));
} catch (LicenseSpringException e) {
    log.error(e.getCause().getMessage());
}

```

## changeOAuthClientSecret

Changes the OAuth Client Secret used for auth -> in case you have a rotating secret

```java
service.changeOAuthClientSecret("otherClientSecret");
```


[title] Setting Up User-Based Licensing
[path] SDKs/Tutorials/Licensing Scenarios/

User-based licensing allows software or service assigned to **license users**. Unlike traditional licensing protected with a license key, this approach focuses on the users themselves, making it ideal for tracking, activation limits, and management.

:::hint{type="success"}
This guide walks you through **creating a user-based product, issuing licenses, and assigning users** in LicenseSpring.&#x20;
:::

:::hint{type="info"}
User-Based Licenses can still be node-locked, since LicenseSpring still supports&#x20;
:::

## **1. Create a User-Based Product**

1. Navigate to the **Products** tab in the dashboard.
2. Click **Add New Product** (top-right corner).

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Pkd2yUOCejjiKpiupdGr__image.png)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/CvL7XFN35SkM3RAUltIfH_image.png)

**Complete the required fields:**

- **Product Name**
- **Product Code**

**Optional configurations:**

1. **Floating Timeout** (minutes): for floating licenses, determines how often the end-user app checks the license to remain registered.
2. Product has trial period(You can set the trial period)
3. Product has file

- [x] **Click&#x20;****Next****&#x20;to confirm.**


:::hint{type="danger"}
Set the **Authorization Method&#x20;**&#x74;o **User:&#x20;**&#x54;his ensures that licenses for this product will be managed on a per-user basis, which is required for user-based licensing.&#x20;
:::

- Your product will now appear in the list with **Authorization Method: USER**, indicating it’s a user-based product.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/1LCFHw8Z82Y0HODuV0fin_image.png)

## **2. Issue a User-Based License**

1. Go to the **Licenses** page and click **Issue Licenses**.
2. Fill in required fields:

- **Order ID**
- **Order Reference**

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/opcmbFHzvcaOt6YQu34e-_image.png)

**Optional:**

- Assign a **License Manager** for the order
- Add a customer to the order
- Link the order to a customer account

* [x] **Click&#x20;****Next****.&#x20;**

## **3. Add Products to the License**

**In this second step,&#x20;**&#x79;ou can add the product to the license, as illustrated in the image below.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/vH8uq8GyTQ0jiGh79Znub_image.png)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/xZJFRnAMcscfTC1xAkcps_image.png)

1. Select the **user-based product&#x20;**&#x79;ou created earlier, as illustrated in the screenshot above.

Optional settings:

- **License Policy**
- **Air-Gapped Option**
- **Custom License Values**

* [x] **Click&#x20;****Confirm****&#x20;(top-right) to finalize.**


- The newl&#x79;**&#x20;created product&#x20;**&#x77;ill appear in the product list, as illustrated in the screenshot below.&#x20;

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/dw9rRLAR27CCIFn1Tcco7_image.png)

- Click **Next** review all order information, and then select **Confirm&#x20;**&#x74;o complete the steps.&#x20;

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/9prGrXFTiVMCSIESRyfpD_image.png)

:::hint{type="warning"}
At this point, the license exists but **no user is assigned yet**. Under **License Key / User**, it will show **Not Assigned** as illustrated in the screenshot above.&#x20;
:::

## **4. Assign a User to the License**

1. Navigate to the **Licenses** section.
2. Select the **user-based license** you want to assign.
3. Click **Assign License User**.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/VK1RKuMwXnDr1JqhZqeZB_image.png)

Either:

1. **Select&#x20;**&#x61;n existing user
2. **Create** a new user

Once completed, the license will show **the assigned user&#x20;****e.g.testuser\@licensespring.com.&#x20;**&#x50;lease note that only users with **License Manager permissions&#x20;**&#x63;an assign licenses to other users.&#x20;

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/74U1kYHnCIOsfL6Uhpy6o_image.png)

:::hint{type="success"}
Users with License Manager permissions can refer to [**this guide**](https://app.archbee.com/docs/FbT_Z5Cu33D-LVZx1fRkU/zkt4QJyVO0_fjwGsvRoBn) for instructions on assigning users and managing the User Portal.&#x20;
:::




[title] Java
[path] SDKs/Tutorials/Getting Started/

In this tutorial, we'll walk you through the step-by-step process of activating your LicenseSpring license using the LicenseSpring Java SDK.&#x20;

This straightforward guide aims to provide you with a clear understanding of how to effectively utilize the LicenseSpring Java SDK and seamlessly integrate it into your product.

By the time you finish this tutorial, you'll be equipped to easily activate, deactivate, and perform license checks from your Java program.

If you run into trouble at any point of the tutorial, just [**submit a support ticket**](https://licensespring.zendesk.com/hc/en-us/requests/new), and we'll be happy to help. Our dedicated support team is here to assist you every step of the way.&#x20;

Let's get started and unlock the full potential of licensing and entitlement management in your Java application.

## Prerequisites:

Since we will be using Java in IntelliJ  on Windows for this tutorial, it is required we have the proper IDE and JDK downloaded.

- Download [**IntelliJ IDEA Community Edition 2022**](https://www.jetbrains.com/idea/download/?section=windows)
- Download [**Java JDK**](https://www.oracle.com/ca-en/java/technologies/downloads/) (For this tutorial, we will use Java SE Development Kit 18.0.1.1)


[title] Device
[path] Management API/


[title] Update Device Variable
[path] Management API/Device/Device Variables/

Updates a device variable, if requesting manager has access permissions to it.

**URL**: `/api/v1/device-variables/{id}/`

**Method**: `PATCH`

### Parameters:

- `variable` - String
- `value` - String

### Data Example:

```json
{
    "variable": "v7",
    "value": "ggg"
}
```

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "id": 2018,
    "created_at": "2021-02-01T07:24:07.617161Z",
    "variable": "v7",
    "value": "ggg",
    "device": 1112
}
```


[title] Webhooks
[path] Events API/

Events are exposed and dispatched through our webhooks service where the vendor platform user can configure an endpoint listener and a list of events happening in your LicenseSpring account which will be dispatched to that endpoint URL. HTTPS is used to send webhook events to your app as a JSON payload.

:::hint{type="warning"}
This is Enterprise feature only. For more information, please contact sales.
:::

## Setup

Webhooks can be configured in the vendor platform under Settings > Webhooks.

To start receiving webhook events in your app you need to create and register a webhook endpoint using the webhooks dashboard. Set up an HTTPS endpoint function that can accept webhook requests so that it handles POST requests with a JSON payload consisting of an event object.

![Webhook configuration panel](https://lh7-us.googleusercontent.com/r1nxsEyHSJ28miehg4n6oecSiwHC-QwT67p-4FlyRvwBmTO3visyIKmGdO27WD4bo1J3ZaXz9-XlacvVl1aVhGzluMWO0nwLYwBg4UxEPtciCuXDd7Fnoob8vKnPu2XCew4qNyacK3FksR3hn8gK2Hs "Webhook configuration panel")

Along with configuration view, the webhooks panel will display history of sent events and option to rollover the secret key needed to verify the webhook data authenticity.

![Webhook details view](https://lh7-us.googleusercontent.com/q8nt6WwWzd3c1uu1ymm7J_DRiToUrSrtYPIg9in0YiaWToVzw5-SxWkxQ3MCeLzeftyPdOsPbPPTQ3C46No6x-iivTf4g-rLLYIbfYaZEynkFtQf290tOMpx3ifiwwEyck4gEp1dgZdCOPt6PO51v3Y "Webhook details view")

## Instructions

### Handle duplicate events

Webhook endpoints might occasionally receive the same event more than once. You can guard against duplicated event receipts by making your event processing idempotent. One way of doing this is logging the events you’ve processed, and then not processing already-logged events.

### Only listen to event types your integration requires

Configure your webhook endpoints to receive only the types of events required by your integration. Listening for extra events (or all events) puts undue strain on your server and we don’t recommend it.

### Receive events with an HTTPS server

If you use an HTTPS URL for your webhook endpoint, LicenseSpring validates that the connection to your server is secure before sending your webhook data. For this to work, your server must be correctly configured to support HTTPS with a valid server certificate.

### Roll endpoint signing secrets periodically

The secret key used for verifying that events come from LicenseSpring is rollable. You can choose to immediately expire the current secret key or delay its expiration for up to 24 hours to allow yourself time to update the verification code on your server. During this time, multiple secrets are active for the endpoint. LicenseSpring generates one signature per secret until expiration. To keep them safe, we recommend that you roll secret keys periodically, or when you suspect a compromised secret key.

### Verify events are sent from LicenseSpring

Verify webhook signatures to confirm that received events are sent from LicenseSpring. LicenseSpring signs webhook events it sends to your endpoints by including a signature in each event’s Licensespring-Signature header. This allows you to verify that the events were sent by LicenseSpring, not by a third party. You can verify signatures either using our official libraries, or verify manually using your own solution. The secret key for each endpoint can be found in the webhooks dashboard.

### Verifying signatures using our official SDKs

:::hint{type="info"}
At the moment, verification of a webhook signature is included in Python SDK only.
:::

You perform the verification by providing the event payload, the Licensespring-Signature header, and the endpoint’s secret. If verification fails, you get an error. LicenseSpring requires the raw body of the request to perform signature verification. If you’re using a framework, make sure it doesn’t manipulate the raw body. Any manipulation to the raw body of the request causes the verification to fail.

```python
from licensespring.webhook import Webhook
from licensespring.webhook.error import SignatureVerificationError
from flask import Flask, request

# Using Flask
# Signing key is set as LICENSESPRING_SIGNING_SECRET env var
@app.route('/licensespring/webhooks/', methods=['POST'])
def licensespring_webhooks():
    licensespring_signature = request.headers.get('Licensespring-Signature')

    try:
        event = Webhook.get_event(
            payload=request.get_data(as_text=True),
            sig_header=licensespring_signature,
            secret=os.environ['LICENSESPRING_SIGNING_SECRET'])
    except SignatureVerificationError:
        return ('Signature is not valid.', 400)

    # Handle the event
    print('Received event {} ({}) from LS with data: {}'.format(
      event.get('event'), 
      event.get('id'), 
      event.get('data')
    ))

    return 'Webhook processed.'
```

### Verifying signatures manually

The Licensespring-Signature header included in each signed event contains a timestamp and one or more signatures that you must verify. The timestamp is prefixed by t=, and each signature is prefixed by a scheme. Schemes start with v, followed by an integer. Currently, the only valid live signature scheme is v1.

```none
t=1706880193,v1=b5125c98c3b58e09bdbe3615057ee2b22f421e67d9ee5791cc7d2d43bfd6363f
```

LicenseSpring generates signatures using a hash-based message authentication code (HMAC) with SHA-256. To prevent downgrade attacks, ignore all schemes that are not v1.

You can have multiple signatures with the same scheme-secret pair when you roll an endpoint’s secret, and keep the previous secret active for up to 24 hours. During this time, your endpoint has multiple active secrets and LicenseSpring generates one signature for each secret.

To create a manual solution for verifying signatures, you must complete the following steps:

**Step 1: Extract the timestamp and signatures from the header**

Split the header using the `,` character as the separator to get a list of elements. Then split each element using the `=` character as the separator to get a prefix and value pair.

The value for the prefix t corresponds to the timestamp, and v1 corresponds to the signature (or signatures). You can discard all other elements.

**Step 2: Prepare the  string**

The `signed_payload` string is created by concatenating:

- The timestamp (as a string)
- The character `.`
- The actual JSON payload (that is, the request body)

**Step 3: Determine the expected signature**

Compute an HMAC with the SHA256 hash function. Use the endpoint’s signing secret as the key, and use the `signed_payload` string as the message.

**Step 4: Compare the signatures**

Compare the signature (or signatures) in the header to the expected signature. For an equality match, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance.

:::CodeblockTabs
```python
import hmac
import json
import time
from hashlib import sha256


def secure_compare(val1, val2):
    return hmac.compare_digest(val1, val2)


class SignatureVerificationError(Exception):
    def __init__(self, message, sig_header, payload):
        self.message = message
        self.sig_header = sig_header
        self.payload = payload

    def __str__(self):
        return self.message

    def __repr__(self):
        return str(self)


class WebhookSignature:
    EXPECTED_SCHEME = "v1"

    @staticmethod
    def compute_signature(payload, secret):
        mac = hmac.new(
            secret.encode("utf-8"),
            msg=payload.encode("utf-8"),
            digestmod=sha256,
        )
        return mac.hexdigest()

    @staticmethod
    def get_timestamp_and_signatures(header, scheme):
        list_items = [i.split("=", 2) for i in header.split(",")]
        timestamp = int([i[1] for i in list_items if i[0] == "t"][0])
        signatures = [i[1] for i in list_items if i[0] == scheme]
        return timestamp, signatures

    @classmethod
    def verify_header(cls, payload, header, secret, tolerance=None):
        try:
            timestamp, signatures = cls.get_timestamp_and_signatures(
                header, cls.EXPECTED_SCHEME
            )
        except Exception:
            raise SignatureVerificationError(
                "Unable to extract timestamp and signatures from header",
                header,
                payload,
            )

        if not signatures:
            raise SignatureVerificationError(
                "No signatures found with expected scheme {}".format(
                    cls.EXPECTED_SCHEME
                ),
                header,
                payload,
            )

        signed_payload = "%d.%s" % (timestamp, payload)
        expected_sig = cls.compute_signature(signed_payload, secret)
        if not any(secure_compare(expected_sig, s) for s in signatures):
            raise SignatureVerificationError(
                "No signatures found matching the expected signature for payload",
                header,
                payload,
            )

        if tolerance and timestamp < time.time() - tolerance:
            raise SignatureVerificationError(
                "Timestamp outside the tolerance zone ({})".format(timestamp),
                header,
                payload,
            )

        return True


class Webhook:
    DEFAULT_TOLERANCE = 300  # 5 minutes

    @staticmethod
    def get_event(payload, sig_header, secret, tolerance=DEFAULT_TOLERANCE):
        WebhookSignature.verify_header(payload, sig_header, secret, tolerance)
        return json.loads(payload)


event = Webhook.get_event(
    payload=_PAYLOAD_GOES_HERE_,
    sig_header=_LICENSESPRING_SIGNATURE_HEADER_GOES_HERE_,
    secret=_SIGNING_KEY_GOES_HERE_,
    tolerence=_OPTIONAL_TOLERENCE_GOES_HERE_,
)
```

```javascript
const crypto = require('node:crypto');

const hmacSHA256 = (key, data) => crypto.createHmac('sha256', key).update(data).digest('hex');

function secureCompare(val1, val2) {
    try {
        return crypto.timingSafeEqual(Buffer.from(val1), Buffer.from(val2));
    } catch (e) {
        // Handles the case where the inputs are of different lengths
        return false;
    }
}

function computeSignature(payload, secret) {
    return hmacSHA256(secret, payload);
}

function getTimestampAndSignatures(header, scheme) {
    const listItems = header.split(',').map(i => i.split('='));
    const timestamp = parseInt(listItems.find(i => i[0] === 't')[1], 10);
    const signatures = listItems.filter(i => i[0] === scheme).map(i => i[1]);
    return { timestamp, signatures };
}

function verifyHeader(payload, header, secret, tolerance = 300) { // Default tolerance of 5 minutes
    let timestamp, signatures;
    try {
        ({ timestamp, signatures } = getTimestampAndSignatures(header, 'v1'));
    } catch (error) {
        throw new Error('Unable to extract timestamp and signatures from header');
    }

    if (!signatures.length) {
        throw new Error('No signatures found with expected scheme v1');
    }

    const signedPayload = `${timestamp}.${payload}`;
    const expectedSig = computeSignature(signedPayload, secret);

    const isSignatureValid = signatures.some(sig => secureCompare(expectedSig, sig));
    if (!isSignatureValid) {
        throw new Error('No signatures found matching the expected signature for payload');
    }

    if (tolerance && timestamp < (Date.now() / 1000) - tolerance) {
        throw new Error(`Timestamp outside the tolerance zone (${timestamp})`);
    }

    return true;
}

function getEvent(payload, sigHeader, secret, tolerance = 300) {
    verifyHeader(payload, sigHeader, secret, tolerance);
    return JSON.parse(payload);
}

// Usage example:
try {
    const event = getEvent(
        payload, // _PAYLOAD_GOES_HERE_
        sigHeader, // _LICENSESPRING_SIGNATURE_HEADER_GOES_HERE_
        secret, // _SIGNING_KEY_GOES_HERE_
        tolerance // _OPTIONAL_TOLERANCE_GOES_HERE_
    );
    // Process event...
} catch (error) {
    console.error(error.message);
}
```
:::

### Preventing replay attacks

A replay attack is when an attacker intercepts a valid payload and its signature, then re-transmits them. To mitigate such attacks, LicenseSpring includes a timestamp in the Licensespring-Signature header. Because this timestamp is part of the signed payload, it’s also verified by the signature, so an attacker can’t change the timestamp without invalidating the signature. If the signature is valid but the timestamp is too old, you can have your application reject the payload.

Our SDKs have a default tolerance of 5 minutes between the timestamp and the current time. You can change this tolerance by providing an additional parameter when verifying signatures.

### Quickly return a 2xx response

Quickly return a successful status code (2xx) prior to any complex logic that could cause a timeout (timeout occurs after 20 seconds). In the event of a timeout the webhook will be logged with `408 Request Timeout` status code.


[title] Local License File
[path] SDKs/Tutorials/Best Practices/

After license activation the SDK creates an encrypted file that contains license information. This article provides information about the local license file and data location.

See also: [**Security and Cryptographic Providers**](docId\:fUMkiWpHDWaP4Of5I6S7Q) for more information about license encryption and [**Custom License Storage**](docId:5rgmpnpkkSyPdlzaWVlHz) for information about alternative ways to save license.&#x20;

## Prerequisites

1. Completed the [**Getting Started**](docId\:LSFY9tQ3vfq4ROOW9sHkd) Tutorial, specifically:
   - Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
   - Created a `LicenseID` using either `LicenseID::fromKey` or `LicenseID::fromUser` function, depending on the activation method you prefer.
   - Implemented basic license management, including license activations, deactivations, and both online and local license checks.

## Default Data Location

The location of the license file depends on the operating system in use.

On Windows, the default SDK data location is: **\{SystemDrive}:/Users/\{UserName}/AppData/Local/LicenseSpring/\{ProductCode}**

On Linux, the default SDK data location is: **HOME/.LicenseSpring/LicenseSpring/\{ProductCode}**

On macOS, the default SDK data location is: **\~/Library/Application Support/LicenseSpring/\{ProductCode}**

To get the location and name of local license file use the following method:

:::CodeblockTabs
```cpp
auto dataLocation = licenseManager->dataLocation();
auto fileName = licenseManager->licenseFileName();
```

```csharp
var path = LicenseManager.GetInstance().DataLocation;
var name = LicenseManager.GetInstance().LicenseFileName;
```

```swift
let file = manager.licenseFile
```

```python
manager = LicenseManager(conf)
folder_path = manager.data_location()
file_name = manager.license_file_name()

print("data folder path: ",folder_path)
print("data file name: ",file_name)


```

```java
String DEFAULT_DIR = "LicenseSpring";
String DEFAULT_LICENSE_PATH = Paths.get(DEFAULT_DIR, productCode, LICENSE_KEY)
  .toAbsolutePath()
  .toString();
```
:::

## Changing Data Location

### Using License Manager

To change the location of local license file, use:

:::CodeblockTabs
```cpp
licenseManager->setDataLocation( L"my/license/path" );
licenseManager->setLicenseFileName( L"MyLicense.lic" );
```

```csharp
LicenseManager.GetInstance().DataLocation = "my/data/location";
LicenseManager.GetInstance().LicenseFileName = "MyLicense.lic";
```

```python
manager.set_data_location("my/data/location")
manager.set_license_file_name("cool_name")
```

```java
LicenseSpringConfiguration config = LicenseSpringConfiguration.builder()
  .licenseFilePath("<customLicenseFilePath>")
  .build();
```
:::

You can also delete all files created by SDK using the **clearLocalStorage&#x20;**&#x6D;ethod:

:::CodeblockTabs
```cpp
licenseManager->clearLocalStorage();
```

```csharp
LicenseManager.GetInstance().ClearLocalStorage();
```

Swift

```swift
try manager.clearLocalStorage()
```

```python
manager.clear_local_storage()
```

```java
licenseManager.clearLocalStorage();
```
:::

### Using Extended Options

If preferred, it is also possible to adjust the location of the local license file before the creation of the `LicenseManager` object in the C++ SDK. This is possible by constructing the `ExtendedOptions` object with the license file path as the lone parameter:

```cpp
ExtendedOptions options = ExtendedOptions(licenseFilePath);
```

Alternatively, it is possible to set the license file path after the `ExtendedOptions` using the the `setLicenseFilePath()` method as follows:

```cpp
options.setLicenseFilePath(licenseFilePath);
```

## License File Corruption

In case the license file gets corrupted during encryption or writing, local license data could be lost. To prevent this, you can check if the local license file is corrupted either on every license file write through a flag in `ExtendedOptions`, or whenever you want.

:::CodeblockTabs
```cpp
// check if license file is corrupted
bool isCorrupted = licenseManager::isLicenseFileCorrupted();

// enable check on every license file write
ExtendedOptions extendedOptions;
extendedOptions.enableLicenseCorruptionCheck( true );

```

```python
manager.is_license_file_corrupted()
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x54;his introduces a runtime overhead due to decrypting an encrypted string.
:::

## Usage Scenarios

Changing the data location allows to implement different scenarios, making the license file acessible by certain users and applications.

### Sharing the License Between Users

The default data location makes the license available for the current user only. To make it available for all users of the device, set a path that all users can acess, e.g.:

:::CodeblockTabs
```cpp
licenseManager->setDataLocation( L"C:\Users\Public\{Product Code}" );
```

```csharp
LicenseManager.GetInstance().DataLocation = "C:\Users\Public\{Product Code}";
```

Swift

```swift
configuration.licenseDirectoryPath = URL(fileURLWithPath: "/Users/Shared/shared_location")
```

```python
manager = LicenseManager(conf)

manager.set_data_location(f"C:\Users\Public\{Product Code}"

```

```java
LicenseSpringConfiguration config = LicenseSpringConfiguration.builder()
  .licenseFilePath("C:/Users/Public/{Product Code}")
  .build();
```
:::

### Sharing the License Between Applications

When you have multiple apps that use LicenseSpring, you can provide a single license for all products. If the user activates a license for one product, the other apps could access the license without license reactivation. To achieve this, make the data location path not product-dependent:

:::CodeblockTabs
```cpp
licenseManager->setDataLocation( L"C:/Users/{UserName}/AppData/Local/LicenseSpring/{CompanyName}" );
```

```csharp
LicenseManager.GetInstance().DataLocation = "C:/Users/{UserName}/AppData/Local/LicenseSpring/{CompanyName}";
```

Swift

```swift
configuration.licenseDirectoryPath = URL(fileURLWithPath: "/Users/xxx/shared_location")
```

```python
manager = LicenseManager(conf)

manager.set_data_location(f"C:/Users/{UserName}/AppData/Local/LicenseSpring/{CompanyName}")

```

```java
LicenseSpringConfiguration config = LicenseSpringConfiguration.builder()
  .licenseFilePath("C:/Users/{UserName}/AppData/Local/LicenseSpring/{CompanyName}")
  .build();
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x43;urrently license files created by different SDKs are not compatible. Make sure to store the license files created by different SDKs separately.&#x20;
:::

### &#xD;

:::hint{type="danger"}
**LocalLicenseException&#x20;**&#x77;ill be thrown if the SDK attempts to read a license file created by another SDK. It also occurs when the local license file is damaged or cannot be loaded or saved.
:::


[title] Python Hardware (Device) IDs
[path] SDKs/Python SDK/

This library provides preconfigured hardware identity providers:

- `HardwareIdProvider` (default)
- `PlatformIdProvider`
- `HardwareIdProviderSource` (recommended)

You can set the desired hardware identity provider when initializing the APIClient:

```python
from licensespring.hardware import PlatformIdProvider

api_client = APIClient(api_key="_your_api_key_", shared_key="_your_shared_key_", hardware_id_provider=PlatformIdProvider)
```

It also supports their customization and creation of your own hardware id provider.

:::hint{type="warning"}
On the next major version release `HardwareIdProviderSource` will be set as the **default** `hardware_id_provider`.
:::



### HardwareIdProvider

Uses [**uuid.getnode()**](https://docs.python.org/3/library/uuid.html#uuid.getnode) to generate unique ID per device as described:

:::BlockQuote
Get the hardware address as a 48-bit positive integer. The first time this runs, it may launch a separate program, which could be quite slow. If all attempts to obtain the hardware address fail, we choose a random 48-bit number with the multicast bit (least significant bit of the first octet) set to 1 as recommended in RFC 4122. “Hardware address” means the MAC address of a network interface. On a machine with multiple network interfaces, universally administered MAC addresses (i.e. where the second least significant bit of the first octet is unset) will be preferred over locally administered MAC addresses, but with no other ordering guarantees.
:::

All of the methods exposed by `HardwareIdProvider`:

```python
class HardwareIdProvider:
    def get_id(self):
        return str(uuid.getnode())

    def get_os_ver(self):
        return platform.platform()

    def get_hostname(self):
        return platform.node()

    def get_ip(self):
        return socket.gethostbyname(self.get_hostname())

    def get_is_vm(self):
        return False

    def get_vm_info(self):
        return None

    def get_mac_address(self):
        return ":".join(("%012X" % uuid.getnode())[i : i + 2] for i in range(0, 12, 2))

    def get_request_id(self):
        return str(uuid.uuid4())
```

### HardwareIdProviderSource

Utilizes a proprietary [**in-house algorithm**](https://pypi.org/project/licensespring-hardware-id-generator/) for our SDKs

```python
class HardwareIdProviderSource(HardwareIdProvider):
    def get_id(self):   
        hardware_id = get_hardware_id(HardwareIdAlgorithm.Default)
        
        if logging.getLogger().hasHandlers():
            logs = get_logs()
            version = get_version()
            logging.info("Version: ",version)
            logging.info("Hardware ID:",hardware_id)
            for log_line in logs:
                logging.info(log_line)
    
        return hardware_id
```

### Customization

Extend any of the preconfigured hardware identity providers, overwrite the methods you want and provide it when initializing the APIClient:

```python
class CustomHardwareIdProvider(HardwareIdProvider):
    def get_id(self):
        return "_my_id_"

api_client = APIClient(api_key="_your_api_key_", shared_key="_your_shared_key_", hardware_id_provider=CustomHardwareIdProvider)
```

```python
class CustomHardwareIdProvider(HardwareIdProvider):
    def get_id(self):
        return "_my_id_"

api_client = APIClient(api_key="_your_api_key_", shared_key="_your_shared_key_", hardware_id_provider=CustomHardwareIdProvider)
```


[title] Management SDK
[path] SDKs/Java SDK/Java Modules/

License management is a module that provides APIs for generating license keys, placing, searching and updating orders as well as licenses. See [**Management API**](docId\:abk8afS7gBMtujL_Rd_4p) for more information on the API.

:::hint{type="danger"}
License Management APIs should not be implemented in application distributions. Keep your management keys safe.
:::

If you wish to use license management in your Maven/Gradle project, use this snippet:

:::CodeblockTabs
```xml
     <dependencies>
       <dependency>
            <groupId>com.licensespring</groupId>
            <artifactId>licensespring-license-management</artifactId>
            <version>2.16.1</version>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>jdk-java</id>
            <url>https://licensespring-maven.s3.eu-central-1.amazonaws.com/</url>
        </repository>
    </repositories>

```

```java
repositories {
    mavenLocal()
    maven {
        url = 'https://licensespring-maven.s3.eu-central-1.amazonaws.com/'
    }
}

dependencies {
    implementation 'com.licensespring:licensespring-license-management:2.16.1'
}
```
:::

*Javadoc, jar and OSGi bundle downloads can be found at:&#x20;*[**Javadoc & Downloads**](docId\:Dm-Ksn9S-VVHGLpYWSm5x)

## Initializing the Management Client

There is only **one parameter** needed to initialize the `ManagementConfiguration`:

- `managementKey`, your company management API key

Management key is available to you in the LicenseSpring web platform under "Settings -> Keys" section.

**Optional** parameter:

- `requestLogging` default is `Logger.Level.NONE`
- `proxyPort` and `proxyHost` used to setup a forward proxy, see more in [**Java Advanced Usage**](docId\:mqLRngvkrEpJ5IVdGUpt0)
- `requestTimeout` set the timeout of requests make to API (in seconds), default is 10 seconds

```java
ManagementConfiguration configuration = ManagementConfiguration.builder()
                .managementKey("management-key")
                .build();

// if you want to see logs of the requests sent to Management API
// turn the logging in the configuration property
ManagementConfiguration configuration = ManagementConfiguration.builder()
                .managementKey("management-key")
                .requestLogging(Logger.Level.FULL)
                .build();
```

## License Management

Licenses can be managed through `LicenseService` object. You can make the `LicenseService` object by passing the configuration you made before.

```java
LicenseService licenseService = new LicenseService(configuration);
```

### searchLicenses(SearchLicensesRequest request)

This method returns the paginated result that contains a list of licenses that satisfy your request. `SearchLicensesRequest` can be made with the builder.

```java
// example of a request with no filters requirements, by default it returns 20 licenses
SearchLicensesRequest request = SearchLicensesRequest.builder()
                .build();

SearchResult<BackOfficeLicense> response = licenseService.searchLicenses(request);

// example of a more complex request
SearchLicensesRequest request = SearchLicensesRequest.builder()
                .licenseKeyContains("GGGG")
                .licenseUserTrueEmailContains("@company.com")
                .limit(1)
                .customerCompanyNameContains("company")
                .build();

// example with a request with all possible queries except orderBy (example below)
// note that you can set as many fields as you want to
SearchLicensesRequest request = SearchLicensesRequest.builder()
                .licenseKey("GGGG-HHHH-FFFF")
  				// if you have multiple companies under your control, 
  				// you can specify which companies licenses you want to search 
  				// by putting in the company code
                .company(1)   
				// if you want to gather specific licenses by their ids
				// you can put a coma separated list of license ids
				.idIn("1593781774572379,1597395059215709,1597395059216729")
  				.customerCompanyNameContains("Enterprise")
                .customerEmail("@company.com")
                .customerId(12)
                .customerNameContains("John")
                .customerReferenceContains("reference")
                .licenseKeyContains("HHHHH")
                .licenseKeyStartsWith("GGGG")
				// if set to true, the result will contain only user-based licenses
				// if set to false, the result will contain only key-based licenses
				.licenseKeyIsNull(true)
                .licenseUserEmail("john@company.com")
                .licenseUserEmailContains("company")
                .licenseUserEmailStartsWith("john")
                .orderStoreId("123456789101112")
                .orderStoreIdContains("456")
                .orderStoreIdStartsWith("123")
				// case insensitive
				.noteContains("part of the note")
				// if true, the result will contain only floating licenses
				// if false, the result will contain only non-floating licenses
				.isAnyFloating(true)
  				// how many licenses you want to get at most
  				// default is 20
                .limit(3)
  				// offset from the beggining of the list of results
  				// default is 0
                .offset(1)
                .build();


// example of ordering results
// ascending order by the attribute created_at
try {
	SearchLicensesRequest request = SearchLicensesRequest.builder()
                .limit(15)
                .orderBy("created_at")
                .build();
} catch (LicenseSpringSortingException e) {
    log.error(e.getCause().getMessage());
}

// descending order by the attribute created_at
try {
	SearchLicensesRequest request = SearchLicensesRequest.builder()
                .limit(15)
                .orderBy("created_at")
                .sortDescending(true)
                .build();
} catch (LicenseSpringSortingException e) {
    log.error(e.getCause().getMessage());
}

// example of a wrong sort attribute, Builder will throw exception
try {
  	SearchLicensesRequest request = SearchLicensesRequest.builder()
                    .orderBy("wrong_filter")
                    .build();
} catch(LicenseSpringSortingException ex) {
  	log.error("Wrong filter used in searching licenses, see documentation on kwiki.");
}
```

Possible order options:

- `id`
- `status`
- `customer__email`
- `customer__company_name`
- `customer__reference`
- `created_at`
- `updated_at`
- `active`
- `enabled`
- `time_activated`
- `time_disabled`
- `max_activations`
- `times_activated`
- `valid_duration`
- `validity_period`
- `license_type`
- `enable_maintenance_period`
- `maintenance_duration`
- `maintenance_period`
- `is_trial`
- `max_consumptions`
- `total_consumptions`
- `subscription_id`
- `last_check`
- `prevent_vm`
- `allow_overages`
- `max_overages`
- `reset_consumption`
- `consumption_period`
- `trial_days`
- `is_floating`
- `is_floating_cloud`
- `floating_users`
- `note`
- `max_license_users`
- `order`
- `order_item`
- `license_key`
- `disabled_user`

If you set the `sortDescending` field to true, the order of the results will be descending, default order is ascending.

### paginateThroughAllLicenses(SearchLicensesRequest request)

This method goes through all pages of the search result and puts all licenses in a list that is then returned. Should be used if there is a need for all licenses that satisfy the request so the user doesn't have to execute the search n times increasing the offset in the initial result.

```java
SearchLicensesRequest request = SearchLicensesRequest.builder()
                .licenseKeyContains("GGGG")
                .customerCompanyNameContains("company")
                .build();

List<BackOfficeLicense> licenses = licenseService.paginateThroughAllLicenses(request);
```

### disableAllLicenses(Long\[] licenseIds)

Disables all the licenses whose ids are listed in the argument. This sets all the devices linked to the license to not active, sets the user who disabled the license, turns license status to inactive and sets the `time_disabled` field to now. Returns true if disabling was successful, false if disabling failed.

```java
Long[] licenseIds = {1234567890101112L, 12345678901011121L};

if (licenseService.disableAllLicenses(licenseIds)) {
    log.info("Disabling of licenses with " + ids + " ids was successful.");
} else {
    // try again, check if ids are correct.
}
```

### getLicense(Long licenseId)

Retrieves detailed information from the server about the license with the provided id.

```java
Long licenseId = 1234567891234567L;

try {
    BackOfficeLicense license = licenseService.getLicense(licenseId);
} catch (LicenseSpringException ex) {
    // license with that id probably doesn't exist
}
```

### updateLicense(Long licenseId, UpdateLicenseRequest request)

Updates the requested fields in the license with the provided id. Returns the updated license. `UpdateLicenseRequest` can be made with the builder.

```java
Long licenseId = 1234567891234567L;

UpdateLicenseRequest request = UpdateLicenseRequest.builder()
      .allowOverages(true)
      .build();

BackOfficeLicense updated = licenseService.updateLicense(licenseId, request);

// request with all possible fields
UpdateLicenseRequest request = UpdateLicenseRequest.builder()
                .allowOverages(true)
                .maxOverages(5)
                .maxConsumptions(100)
                .resetConsumption(true)
                .consumptionPeriod("daily")
                .floatingUsers(2)
                .isFloating(false)    // license can be either floating or floating cloud
                .isFloatingCloud(true)
                .isTrial(true)
                .trialDays(10)
                .enabled(true)
                .enableMaintenancePeriod(true)
                .maintenanceDuration("1year")
                .maxActivations(20)
                .preventVm(true)
                .validDuration("1year")
                .validityPeriod("2020-09-30")
                .build();
        
BackOfficeLicense updated = licensesService.updateLicense(id,request);
```

### patchLicenseFeatures(Long licenseId, PatchLicenseFeaturesRequest request)

Patches the license (product) features available.

Thread carefully when using this method, posting an empty request will remove all features.

```java
// this will erase all features on the license
Long id = 1234567891011121L;  
  
PatchLicenseFeaturesRequest build = PatchLicenseFeaturesRequest.builder().  
        build();  
  
BackOfficeLicense backOfficeLicense = service.patchLicenseFeatures(id, build);

// putting all features from the product on the license
List<LicenseFeaturePatch> features = product.getProductFeatures()  
        .stream()  
        .map(feature -> LicenseFeaturePatch.builder()  
                .productFeature(feature.getCode())  
                .maxConsumption(feature.getMaxConsumption()))  
        .map(LicenseFeaturePatch.LicenseFeaturePatchBuilder::build)  
        .collect(Collectors.toList());  
  
BackOfficeLicense backOfficeLicenseWithFeatures = service.patchLicenseFeatures(id,  
 PatchLicenseFeaturesRequest.builder().productFeatures(features).build());
```

### assignUser(Long licenseId, AssignUserToLicenseRequest licenseUser)

Assigns the provided user to the license with the provided id. `AssignedLicenseUser` can be made with the builder. Only required field is email. Returns a message that can either be :

- "License was successfully assigned and users new password is *password*". This will be returned when user assigned to the license is a first time user and password wasn't set as a field in `AssignUserToLicenseRequest` object, password will be generated from the server and passed in the string. The initial password can also be seen on the LicenseSpring platform. The other use case when this will be returned is when the user assigned to the license already owns at least one license and therefore already has a password, but if the field *password&#x20;*&#x69;n the `AssignUserToLicenseRequest` object was set, than users old password will be rewritten to the new password and sent as a confirmation in the message.
- "License was successfully assigned and user already has a password." This will be returned when the user assigned to the license already has at least one license and therefore already has a password and the *password&#x20;*&#x66;ield in the `AssignUserToLicenseRequest` object wasn't set.

```java
Long licenseId = 1234567891234567L;

// example 1 - first time user with only required parameters
AssignUserToLicenseRequest request = AssignUserToLicenseRequest.builder()
      .email("someemail@gmail.com")
      .build();

// response will be "License was successfully assigned and users new password is *initial_password_that_server_set*."
// password will be random 8 characters including a-z, A-Z, 0-9, and special characters
String response = licenseService.assignUser(licenseId, request);

// example 2 - first time user with all parameters and set password
AssignUserToLicenseRequest request = AssignUserToLicenseRequest.builder()
      .email("someemail@gmail.com")
      .firstName("John")
      .lastName("Doe")
      .phoneNumber("000-111-000")
      .isManager(false)
      .password("password")
      .build();

// response will be "License was successfully assigned and users new password is password."
String response = licenseService.assignUser(licenseId, request);


// example 3 - assigning a user that already exists in the database but changing his password
AssignUserToLicenseRequest request = AssignUserToLicenseRequest.builder()
      .email("someemail@gmail.com")
      .password("password")
      .build();

// response will be License was successfully assigned and users new password is password."
String response = licenseService.assignUser(licenseId, request);

// example 4 - assigning a user that already exists in the databse and not setting the password field
AssignUserToLicenseRequest request = AssignUserToLicenseRequest.builder()
      .email("someemail@gmail.com")
      .build();

// response will be "License was successfully assigned and user already has a password."
String response = licenseService.assignUser(licenseId, request);// this will erase all features on the license
Long id = 1234567891011121L;  
  
PatchLicenseFeaturesRequest build = PatchLicenseFeaturesRequest.builder().  
        build();  
  
BackOfficeLicense backOfficeLicense = service.patchLicenseFeatures(id, build);

// putting all features from the product on the license
List<LicenseFeaturePatch> features = product.getProductFeatures()  
        .stream()  
        .map(feature -> LicenseFeaturePatch.builder()  
                .productFeature(feature.getCode())  
                .maxConsumption(feature.getMaxConsumption()))  
        .map(LicenseFeaturePatch.LicenseFeaturePatchBuilder::build)  
        .collect(Collectors.toList());  
  
BackOfficeLicense backOfficeLicenseWithFeatures = service.patchLicenseFeatures(id,  
 PatchLicenseFeaturesRequest.builder().productFeatures(features).build());
```

### assignMultipleUsers(Long licenseId, AssignMultipleUsersRequest request)

Assigns multiple users to a single license if requesting manager has access permissions to it.

```java
Long licenseId = 1234567891011121L;  
AssignUserData data1 = AssignUserData.builder()  
        .email("user1@company.com")  
        .build();  
  
AssignUserData data2 = AssignUserData.builder()  
        .email("user2@company.com")  
        .build();  
  
AssignUserData[] userData = new AssignUserData[]{data1, data2};  
  
  
AssignMultipleUsersRequest request = AssignMultipleUsersRequest.builder()  
        .emails(userData)
        .sendEmail(false)  
        .build();  
  
List<MultipleAssignmentResponse> responses = service.assignMultipleUsers(licenseId, request);

System.out.println(responses.get(0).getEmail());  
System.out.println(responses.get(0).getNewUser());  
System.out.println(responses.get(0).getPassword());Long licenseId = 1234567891234567L;

// example 1 - first time user with only required parameters
AssignUserToLicenseRequest request = AssignUserToLicenseRequest.builder()
      .email("someemail@gmail.com")
      .build();

// response will be "License was successfully assigned and users new password is *initial_password_that_server_set*."
// password will be random 8 characters including a-z, A-Z, 0-9, and special characters
String response = licenseService.assignUser(licenseId, request);

// example 2 - first time user with all parameters and set password
AssignUserToLicenseRequest request = AssignUserToLicenseRequest.builder()
      .email("someemail@gmail.com")
      .firstName("John")
      .lastName("Doe")
      .phoneNumber("000-111-000")
      .isManager(false)
      .password("password")
      .build();

// response will be "License was successfully assigned and users new password is password."
String response = licenseService.assignUser(licenseId, request);


// example 3 - assigning a user that already exists in the database but changing his password
AssignUserToLicenseRequest request = AssignUserToLicenseRequest.builder()
      .email("someemail@gmail.com")
      .password("password")
      .build();

// response will be License was successfully assigned and users new password is password."
String response = licenseService.assignUser(licenseId, request);

// example 4 - assigning a user that already exists in the databse and not setting the password field
AssignUserToLicenseRequest request = AssignUserToLicenseRequest.builder()
      .email("someemail@gmail.com")
      .build();

// response will be "License was successfully assigned and user already has a password."
String response = licenseService.assignUser(licenseId, request);// this will erase all features on the license
Long id = 1234567891011121L;  
  
PatchLicenseFeaturesRequest build = PatchLicenseFeaturesRequest.builder().  
        build();  
  
BackOfficeLicense backOfficeLicense = service.patchLicenseFeatures(id, build);

// putting all features from the product on the license
List<LicenseFeaturePatch> features = product.getProductFeatures()  
        .stream()  
        .map(feature -> LicenseFeaturePatch.builder()  
                .productFeature(feature.getCode())  
                .maxConsumption(feature.getMaxConsumption()))  
        .map(LicenseFeaturePatch.LicenseFeaturePatchBuilder::build)  
        .collect(Collectors.toList());  
  
BackOfficeLicense backOfficeLicenseWithFeatures = service.patchLicenseFeatures(id,  
 PatchLicenseFeaturesRequest.builder().productFeatures(features).build());
```

### unassignUser(Long licenseId, int licenseUserId)

Unassigns a user from a single license if requesting manager has access permissions to it.

```java
Long id = 1234567891011121L;  
int userId = 1;  
String email = "user@company.com";  
  
service.unassignUser(id,userId);
```

### setUserPassword(int userId, String newPassword)

Sets the license users password to a new value.

```java
int userId = 11;  
String password = "new_pass";  
  
licenseService.setUserPassword(userId,password);
```

### disableLicense(Long id)

Disables the license with the provided id. Will throw exception if license with that id doesn't exist. Sets the status of the license to *disabled*, `time_disabled` to now, all devices set to *inactive&#x20;*&#x61;nd sets the user who disabled the license. Returns true if disabling was successful, false if otherwise.

```java
Long id = 1234567891234567L;

boolean isDeactivated = licenseService.disableLicense(id)int userId = 11;  
String password = "new_pass";  
  
licenseService.setUserPassword(userId,password);
```

### resetLicense(Long id)

Resets the license with the provided id. Sets the status to *inactive*, `times_activated` to 0, and all devices linked to the license to *inactive.*

```java
Long id = 1234567891234567L;

boolean isReset = licenseService.resetLicense(id))
```

### enableLicense(Long id)

Enables the license with the provided id. Returns detailed license information that is now enabled.

```java
Long id = 1234567891234567L;

BackOfficeLicense license = licenseService.enableLicense(id);

```

### resetTotalConsumptions(Long licenseId)

Resets the total consumptions on the license to zero.

```java
Long id = 1234567891011121L;  
  
BackOfficeLicense license = service.resetTotalConsumptions(id);

```

## License Custom Fields Management

To manage custom fields on licenses, call `LicenseCustomFieldsService` methods. Service is available through `LicenseService` class.

```java
// save the LicenseCustomFieldsService as a separate object
LicenseService licenseService = new LicenseService(configuration);  
LicenseCustomFieldsService cfService = licenseService.licenseCustomFieldsService()

// call the service through LicenseService object
... = licenseService.licenseCustomFieldsService().method();

```

### search(SearchLicenseCustomFieldsRequest request)

Searches through all license custom fields and returns the search result which contains all license custom fields that satisfy the request queries.

```java
// basic request 
SearchLicenseCustomFieldsRequest request = SearchLicenseCustomFieldsRequest.builder()  
        .build();  
  
SearchResult<BackOfficeLicenseCustomField> response = cfService.search(request);

// search by license id
Long license = 1234567891011121L;  

SearchLicenseCustomFieldsRequest request = SearchLicenseCustomFieldsRequest.builder()  
        .license(license)  
        .build();  
  
SearchResult<BackOfficeLicenseCustomField> response = cfService.search(request);

// search with all possible queries
Long license = 1234567891011121L;  

SearchLicenseCustomFieldsRequest request = SearchLicenseCustomFieldsRequest.builder()  
        .license(license)
		.limit(5)
		.offset(2)
        .build();  
  
SearchResult<BackOfficeLicenseCustomField> response = cfService.search(request);

```

### paginate(SearchLicenseCustomFieldsRequest request)

Goes through all pages of the search license custom fields response and returns a list with all possible license custom fields that satisfy the request. Makes multiple requests to the server until all results have been found.

```java
SearchLicenseCustomFieldsRequest request = SearchLicenseCustomFieldsRequest.builder()  
        .build();  
  
List<BackOfficeLicenseCustomField> allFields = licenseService.licenseCustomFieldsService().paginate(request);

```

### get(Integer id)

Retrieves license custom field data.

```java
int id = 1;  
  
BackOfficeLicenseCustomField field = cfService.get(id);

```

### create(CreateLicenseCustomFieldRequest request)

Creates a new license custom field.

```java
Long license = 1234567891011121L;  
String value = "value";  
int product = 11;  
  
CreateLicenseCustomFieldRequest request = CreateLicenseCustomFieldRequest.builder()  
        .license(license)  
        .value(value)  
        .productCustomField(product)  
        .build();  
  
BackOfficeLicenseCustomField field = cfService.create(request);

```

### update(Integer id, UpdateCustomLicenseFieldRequest request)

Updates the license custom field.

```java
int id = 6;  
String value = "value";  
  
UpdateCustomLicenseFieldRequest request = UpdateCustomLicenseFieldRequest.builder()  
        .value(value)  
        .build();  
  
cfService.update(id, request);
```

### delete(Integer id)

Deletes the license custom field.

```java
int id = 12;

cfService.delete(id);
```

## Device Management

Devices can be managed through `LicenseService` object. You can make the `LicenseService` object by passing the configuration you made before.

```java
LicenseService service = new LicenseService(configuration);
```

### searchDevices(SearchDevicesRequest request)

This method returns the paginated result that contains a list of devices that satisfy your request. `SearchDevicesRequest` can be made using builder.

```java
// basic request, gets a list of 20 devices.
SearchDevicesRequest request = SearchDevicesRequest.builder()
                .build();

// gets the first 10 devices that are blacklisted
SearchDevicesRequest request = SearchDevicesRequest.builder()
                .blacklisted(true)
                .limit(10)
                .build();

// lists at most 20 devices that are linked with this license
SearchDevicesRequest request = SearchDevicesRequest.builder()
                .license(1234567890101112L)
                .build();

// search by hostname
SearchDevicesRequest request = SearchDevicesRequest.builder()
				.hostname("hostname")
                .build();
				
// search by hardware id
SearchDevicesRequest request = SearchDevicesRequest.builder()
				.hardwareId("G1G1-G1G1-G1G1-G1G1-G1G1-G1G1-G1G1-G1G1-G1G1-G1G1-G1G1-G1G1-G1G1-G1G1-G1G1-G1G1")
                .build();

// gets at most 100 devices with an offset equal to 10 and orders them by the license id attribute in ascending order
try {
	SearchDevicesRequest request = SearchDevicesRequest.builder()
                .limit(100)
                .orderBy("license")
  				.offset(10)
                .build();
} catch (LicenseSpringSortingException e) {
    log.error(e.getCause().getMessage());
}

// lists at most 100 devices that are sorted by the blacklisted in descending order 
try {
	SearchDevicesRequest request = SearchDevicesRequest.builder()
                .limit(100)
                .orderBy("blacklisted")
                .sortDescending(true)
                .build();
} catch (LicenseSpringSortingException e) {
    log.error(e.getCause().getMessage());
}    
List<Device> results = licensesService.searchDevices(request);

```

Possible filters:

- `license`
- `blacklisted`
- `hostname`
- `hardware_id`

The result list can be sorted in descending order if the flag `sortDescending` is set to true. This, of course, only works if `orderBy` is set. Default order is ascending.

### paginateThroughAllDevices(SearchDevicesRequest request)

This method goes through all pages of the search result and puts all devices in a list that is then returned. Should be used if there is a need for all devices that satisfy the request so the user doesn't have to execute the search n times increasing the offset in the initial result.

```java
SearchDevicesRequest request = SearchDevicesRequest.builder()
                .blacklisted(true)
                .build();

List<Device> devices = licenseService.paginateThroughAllDevices(request);
```

### getDevice(Long id)

Gets the device with the provided id.

```java
Long id = 1000100010010010L;
Device device = licenseService.getDevice(id);

log.info(device.getOs());
log.info(device.getMacAddress());
log.info(device.getAppVer());
log.info(device.getExternalIp());
log.info(device.getFloatingLastSeen());
log.info(device.getHardwareId());
log.info(device.getHostname());
log.info(device.getIp());
log.info(device.getLicense());
log.info(device.getSdkBuildVersion());
log.info(device.getType());
log.info(device.getVmInfo());
log.info(device.getDeviceVariables().toString());
log.info(String.valueOf(device.getCreatedAt().getYear()));
log.info(device.getId().toString());
log.info(device.getLastCheck().toString());
log.info(device.getTimeActivated().toString());
log.info(device.getTimeDeactivated().toString());
log.info(device.getUpdatedAt().toString());
log.info(device.getValidityPeriod().toString());
log.info(device.isBlacklisted() ? "blacklisted" : "not blacklisted");
log.info(device.isDeviceActive() ? "active" : "not active");
log.info(device.isFloatingInUse() ? "in use" : "not in use");
log.info(device.isVm() ? "vm" : "not vm");
```

### resetDevice(Long id)

Resets the device.

```java
Long id = 1234567891011121L;  
  
service.resetDevice(id);
```

### blacklistDevice(Long id)

Blacklists the device.

```java
Long id = 1234567891011121L;  
  
service.blacklistDevice(id);
```

## Device Variables Management

To manage device variables, call `DeviceVariablesService` methods. Service is available through `LicenseService` class.

```java
// save the DeviceVariablesService as a separate object
LicenseService licenseService = new LicenseService(configuration);  
DeviceVariablesService dvService = licenseService.deviceVariablesService()

// call the service through LicenseService object
... = licenseService.deviceVariablesService().someMethod();
```

### search(SearchDeviceVariablesRequest request)

Searches through all device variables and returns the search result which contains all device variables that satisfy the request queries.

```java
// basic request 
SearchDeviceVariablesRequest request = SearchDeviceVariablesRequest.builder()  
        .build();  
  
SearchResult<BackOfficeDeviceVariable> response = dvService.search(request);

// search by id
Long id = 1234567891011121L;  

SearchDeviceVariablesRequest request = SearchDeviceVariablesRequest.builder()  
        .device(id)  
        .build();  
  
SearchResult<BackOfficeDeviceVariable> response = dvService.search(request);

// search with all possible queries
Long id = 1234567891011121L;  

SearchDeviceVariablesRequest request = SearchDeviceVariablesRequest.builder() 
        .device(id)
		.limit(5)
		.offset(2)
        .build();  
  
SearchResult<BackOfficeDeviceVariable> response = dvService.search(request);
```

### paginate(SearchDeviceVariablesRequest request)

Goes through all pages of the search device variables response and returns a list with all possible device variables that satisfy the request. Makes multiple requests to the server until all results have been found.

```java
SearchDeviceVariablesRequest request = SearchDeviceVariablesRequest.builder()  
        .build();  
  
List<BackOfficeDeviceVariable> allFields = licenseService.deviceVariablesService().paginate(request);
```

### get(Integer id)

Retrieves device variable data.

```java
Long id = 111L;  
  
BackOfficeDeviceVariable field = dvService.get(id);
```

### create(CreateDeviceVariableRequest request)

Creates a new device variable.

```java
Long device = 1234567891011121L;
  
String variable = "var";  
String value = "val";

CreateDeviceVariableRequest request = CreateDeviceVariableRequest.builder()  
        .device(device)  
        .value(value)  
        .variable(variable)
        .build();  
  
BackOfficeDeviceVariable backOfficeDeviceVariable = dvService.create(request);
```

### update(Integer id, UpdateDeviceVariableRequest request)

Updates the device variable

```java
String variable = "var";  
String value = "val";  
Long id = 111L;  
  
UpdateDeviceVariableRequest request = UpdateDeviceVariableRequest.builder()  
        .variable(variable)  
        .value(updatedValue)  
        .build();  
 
BackOfficeDeviceVariable updatedVariable = dvService.update(id, request);
```

### delete(Integer id)

Deletes the device variable.

```java
Long id = 111L;

dvService.delete(id);
```

## Order Management

All requests for Orders API should be done via the `OrderService` object. You can make the `OrderService` object by passing the configuration you made before.

```java
OrderService orderService = new OrderService(configuration);
```

### searchOrders(SearchOrdersRequest request)

This method returns the paginated result that contains a list of orders that satisfy your request. `SearchOrdersRequest` can be made with builder.

```java
// basic request without special queries, retrieves a list of 20 orders
SearchOrdersRequest request = SearchOrdersRequest.builder()
                .build();

// retrieves a list of at most 20 orders under the company with the id 10
SearchOrdersRequest request = SearchOrdersRequest.builder()
                .company(10)
                .build();

// request with all possible fields except the orderBy
SearchOrdersRequest request = SearchOrdersRequest.builder()
  				// if you have multiple companies under your control, 
                // you can specify which companies licenses you want to search 
                // by putting in the company code               
  				.company(10)
                .customerCompanyName("Company Example Co.")
                .customerCompanyNameContains("Example")
                .customerEmail("john-company@gmail.com")
                .customerEmailContains("company")
                .customerEmailStartsWith("john")
                .customerId(11)
                .customerNameContains("Doe")
                .customerReferenceContains("123")
                .storeId("1234567890101112")
                .storeIdContains("456")
                .storeIdStartsWith("123")
  				// how many orders you want to be retrieved, deafult is 20
                .limit(10)
  				// offset from the beggining of the result
                .offset(1)
                .build();

// sorts the orders in ascending order by the field company
try {
	SearchOrdersRequest request = SearchOrdersRequest.builder()
                .orderBy("company")
                .build();
} catch (LicenseSpringSortingException e) {
    log.error(e.getCause().getMessage());
}

// sorts the orders in descending order by the field customerId
try {
	SearchOrdersRequest request = SearchOrdersRequest.builder()
                .orderBy("customerId")
                .sortDescending(true)
                .build();
} catch (LicenseSpringSortingException e) {
    log.error(e.getCause().getMessage());
}

SearchResult<Order> response = ordersService.searchOrders(request);
```

Possible filters:

- `store_id`
- `store_id__startswith`
- `store_id__icontains`
- `customer__email`
- `customer__email__startswith`
- `customer__email__icontains`
- `company`
- `customer_id`
- `customer_email`
- `customer_company_name`
- `customer_company_name__icontains`
- `customer_reference__icontains`
- `customer_name__icontains`

Default order is ascending, to get descending order set the flag `sortDescending` to true.

### getOrder(Long id)

Returns the order with the provided id.

```java
Long id = 1234567891234567L;

Order order = orderService.getOrder(id);

// there are a lot of fields that can be accessed with a getter
// this is just an example of a few of them
// we advise you to explore all the fields you can get from the order
log.info(order.getCustomerCompany());
log.info(order.getType().name());
log.info(order.getCustomer().getAddress());
log.info(order.getOrderItems().get(0).getProductId());
        
```

### paginateThroughAllOrders(SearchOrdersRequest request)

This method goes through all pages of the search result and puts all orders in a list that is then returned. Should be used if there is a need for all orders that satisfy the request so the user doesn't have to execute the search n times increasing the offset in the initial result.

```java
SearchOrdersRequest request = SearchOrdersRequest.builder()
                .company(10)
                .build();

List<Order> orders = licenseService.paginateThroughAllOrders(request);
        
```

### createOrder(WebhookOrder order)

Creates an `Order` and returns the generated orderId and a list of emails and their respective passwords if the user is new and was listed in the `WebHookOrder`.

```java
// example 1. - simple order with user based license
Customer customer = Customer.builder()
      .email("someemail@gmail.com")
      .build();

UserBasedLicense user = UserBasedLicense.builder()
      .email("anotheremail@gmail.com")
      .build();

OrderLicense license = OrderLicense.builder()
      .licenseType(LicenseType.CONSUMPTION)
      .user(user)
      .maxConsumptions(555)
      .consumptionPeriod("1m")
      .maxActivations(5)
      .build();

OrderItem item = OrderItem.builder()
      .productCode("pc")
      .license(license)
      .build();

WebhookOrder order = WebhookOrder.builder()
      .customer(customer)
      .id("my-application-order-reference-" + Instant.now().toEpochMilli())
      .item(item)
      .build();

CreateOrderResponse response = ordersService.createOrder(order);

log.info(response.getOrderId());
for (UserData data : response.getNewPasswords()) {
  		log.info(data.getEmail() + " -> " + data.getNewPassword());
}

// example 2. - simple key based order
Customer customer = Customer.builder()
        .email("someemail@gmail.com")
        .build();

GenerateLicenseRequest params = GenerateLicenseRequest.builder()
        .product("pc")
        .quantity(5)
        .build();

String[] keys = ordersService.generateLicenseKeys(params);

OrderLicense license = OrderLicense.builder()
        .licenseType(LicenseType.CONSUMPTION)
        .maxConsumptions(666)
        .resetConsumption(true)
        .preventVm(true)
  		// identity is either a LicenseIdentity object or its subclass ActivationLicense object
        .key(identity.getLicenseKey())
        .build();

OrderItem item = OrderItem.builderWith(this::consumptionFactory)
        .productCode("pc")
        .generateLicenses(keys)
        .build();

WebhookOrder order = WebhookOrder.builder()
        .customer(customer)
        .id("my-application-order-reference-" + Instant.now().toEpochMilli())
        .item(item)
        .build();

CreateOrderResponse response = ordersService.createOrder(order);

log.info(response.getOrderId());

private OrderLicense consumptionFactory(LicenseIdentity identity){

        return OrderLicense.builder()
                .licenseType(LicenseType.CONSUMPTION)
                .maxConsumptions(666)
                .allowOverages(true)
                .maxOverages(1666)
                .resetConsumption(true)
                .preventVm(true)
                .key(identity.getLicenseKey())
                .build();
}

// example 3. - this contains all objects needed to create an order 
// but with more verbose fields than just those that are required

Customer customer = Customer.builder()
      .email("someemail@gmail.com")
      .firstName("John")
      .lastName("Doe")
      .companyName("Company Example Co.")
      .reference("reference123")
      .phone("09-123-456-789")
      .build();
        
```

### generateLicenseKeys(GenerateLicenseRequest request)

Returns a String array filled with generated license keys that can be used to place orders. `GenerateLicenseRequest` can be made with builder.

```java
// product and quantity are both required and only fields
GenerateLicenseRequest request = GenerateLicenseRequest.builder()
      .product("pc")
      .quantity(5)
      .build();

String[] keys = orderService.generateLicenseKeys(request);
System.out.println(keys);
```

### addManagerToOrder(Long orderId, AddManagerToOrderRequest request)

Adds a manager to an order.

```java
AddManagerToOrderRequest request = AddManagerToOrderRequest  
        .builder()  
        .email("manager@company.com")  
        .password("password")  
        .build();  
  
Long orderId = 1234567891011121L;  
  
Manager manager = orderService.addManagerToOrder(orderId, request));
```

### exportToCsv(LocalDate from, LocalDate to, String destination)

Makes a request to the server to send the csv file with all orders made in the requested range. Destination is a path where the file should be saved. If the argument is set to null, the SDK will try to save it to the desktop or home if desktop is unavailable. This method returns the filepath where the file was saved. From and to are `LocalDate` types, can be made like this: `LocalDate from = LocalDate.of(GGGG,MM,DD)`

Example of how the csv will be named: `2020-07-01to2020-09-01.csv`

```java
// saves the csv to desktop or home 
String filePath = orderService.exportToCsv(LocalDate.of(2020, 7, 1), LocalDate.of(2020, 9, 1), null);

// saves the csv to custom path
String filePath = orderService.exportToCsv(LocalDate.of(2020, 7, 1), LocalDate.of(2020, 9, 1), "home/user/Downloads/licensespring");
```

### exportToCsv(Range range, String destination)

Makes a request to the server to send the csv file with all orders made in the requested range. Range is an enum with values:`last30`, `last60`, `last180`, `last365`, where numbers specify days (last30 is all orders from the last 30 days). Destination is a path where the file should be saved. If the argument is set to null, the SDK will try to save it to the desktop or home if desktop is unavailable. This method returns the filepath where the file was saved. From and to are `LocalDate` types, can be made like this: `LocalDate from = LocalDate.of(GGGG,MM,DD)`

Example of how the csv will be named: `2020-07-01to2020-09-01.csv`

```java
// saves the csv to desktop or home 
String filePath = orderService.exportToCsv(Range.LAST60, null);

// saves the csv to custom path
String filePath = orderService.exportToCsv(Range.LAST60, "home/user/Downloads/licensespring");
```

## Product Management

Products can be managed through `OrderService` object. You can make the `OrderService` object by passing the configuration you made before.

```java
OrderService orderService = new OrderService(configuration);
```

### searchProducts(SearchProductsRequest request)

This method returns the paginated result that contains a list of products that satisfy your request. `SearchProductsRequest` can be made with builder.

```java
// basic request, no fields required, gets at most 20 products because limit is 20 by default
SearchProductsRequest request = SearchProductsRequest.builder()
                .build();

// gets at most 40 products that are archived
SearchProductsRequest request = SearchProductsRequest.builder()
                .isArchived(true)
  				.limit(40)
                .build();

// gets products, sorts them in ascending order by the isArchived field, and then gets 10 products with an offset of 10
try {
	SearchProductsRequest request = SearchProductsRequest.builder()
                .limit(10)
                .offset(10)
                .orderBy("is_archived")
                .build();
} catch (LicenseSpringSortingException e) {
    log.error(e.getCause().getMessage());
}

// gets products and sorts them by the isArchived field in descending order and sends back first 20 products
try {
	SearchProductsRequest request = SearchProductsRequest.builder()
                .orderBy("is_archived")
                .sortDescending(true)
                .build();
} catch (LicenseSpringSortingException e) {
    log.error(e.getCause().getMessage());
}        


SearchResult<BackOfficeProduct> response = ordersService.searchProducts(request);

// there are a lot of read-only fields at your disposal, these are just some of them
// we encourage you to explore them and see which ones interest you 
for(BackOfficeProduct product : response.getResults()) {
            log.info(product.getAuthorizationMethod());
            log.info(product.getConsumptionPeriod());
            log.info(product.getMaintenanceDuration());
            log.info(product.getShortCode());
            log.info(product.getSubscriptionDuration());
            log.info(product.getValidDuration());
            log.info(product.getCustomFields()[0].getName());
}
```

### getProduct(Long id)

Gets details about the product with specified id.

```java
Long id = 1234567891234567L;

BackOfficeProduct product = orderService.getProduct(id);

// there are a lot of read-only fields at your disposal, these are just some of them
// we encourage you to explore them and see which ones interest you 
log.info(product.getAuthorizationMethod());
log.info(product.getConsumptionPeriod());
log.info(product.getMaintenanceDuration());
log.info(product.getShortCode());
log.info(product.getSubscriptionDuration());
log.info(product.getValidDuration());
log.info(product.getCustomFields()[0].getName());
```

### paginateThroughAllProducts(SearchProductsRequest request)

This method goes through all pages of the search result and puts all products in a list that is then returned. Should be used if there is a need for all products that satisfy the request so the user doesn't have to execute the search n times increasing the offset in the initial result.

```java
SearchProductsRequest request = SearchProductsRequest.builder()
                .isArchived(true)
                .build();

List<BackOfficeProduct> products = licenseService.paginateThroughAllProducts(request);
```

## Installation File Management

Use `OrderService` object to manage installation files.

```java
OrderService orderService = new OrderService(configuration);
```

### searchInstallationFiles(SearchInstallationFilesRequest request)

Searches the `InstallationFiles` by applying the filtering and ordering conditions in the `SearchInstallationFilesRequest` class.

```java
// example of a request with all possible queries
SearchInstallationFilesRequest request = SearchInstallationFilesRequest.builder()  
        .limit(3)  
        .offset(1)  
        .product(1234567891011121L)  
        .orderBy("product")
        .sortDescending(true)  
        .build();  
  
List<BackOfficeInstallationFile> files = orderService.searchInstallationFiles(request).getResults();
```

### paginateThroughAllInstallationFiles(SearchInstallationFilesRequest request)

Goes through all pages of the response and returns a list with all possible installation files that satisfy the request. Makes multiple requests to the server until all results have been found.

```java
SearchInstallationFilesRequest searchRequest = SearchInstallationFilesRequest.builder()  
        .build();   
  
List<BackOfficeInstallationFile> products = orderService.paginateThroughAllInstallationFiles(searchRequest);
```

### getInstallationFile(int id)

Gets the installation file with the provided id.

```java
int id = 1;  
  
BackOfficeInstallationFile file = orderService.getInstallationFile(id);
```

### createInstallationFile(CreateInstallationFileRequest request)

Creates and returns a new `InstallationFile` with the details provided in the request.

```java
Long id = 1234567891011121L;  
  
CreateInstallationFileRequest request = CreateInstallationFileRequest.builder()
	// use Environment enum for options 
        .environment(Environment.MAC)
        .fullLink("https://company.com/product")  
        .hashMd5("hash")  
        .product(id) 
		// needs to be of YYYY-MM-DD format
		// will throw exception otherwise
        .releaseDate("2021-03-15")
        .version("2.8")
        .build();  
  
BackOfficeInstallationFile file = orderService.createInstallationFile(request);
```

## Product Custom Field Management

Use `OrderService.productCustomFieldsService()` method to get a service for managing products custom fields.

```java
// save product custom fields service as an object
ProductCustomFieldsService pcfService = orderService.productCustomFieldsService()

// call it directly without saving the object
Object response = orderService.productCustomFieldsService().method();
```

### search(SearchProductCustomFieldsRequest request)

Searches through all product custom fields and returns the search result which contains all product custom fields that satisfy the request queries.

```java
SearchProductCustomFieldsRequest request = SearchProductCustomFieldsRequest.builder()  
        .limit(10)  
        .product(1234567891011121L)  
        .build();  
  
SearchResult<BackOfficeProductCustomField> result = orderService.productCustomFieldsService().search(request);
```

### get(Integer id)

Retrieves product custom field data.

```java
int id = 11;  
  
BackOfficeProductCustomField backOfficeProductCustomField = pcfService.get(id);
```

### create(CreateProductCustomFieldRequest request)

Creates a new product custom field.

```java
long product = 1234567891011121L;  
String name = "name";  
String defaultValue = "valueByDefualt";  
CreateProductCustomFieldRequest request = CreateProductCustomFieldRequest.builder()  
        .product(product)  
        .name(name)  
        .defaultValue(defaultValue)  
        .build();  
  
BackOfficeProductCustomField field = pcfService.create(request);
```

### update(Integer id, UpdateProductCustomFieldRequest request)

Updates the product custom field.

```java
String updatedName = "updated name";  
String updatedValue = "updated value";  
int id = 18;  
  
UpdateProductCustomFieldRequest request = UpdateProductCustomFieldRequest.builder()  
        .name(updatedName)  
        .defaultValue(updatedValue)  
        .build();
  
BackOfficeProductCustomField updatedField = pcfService.update(id, request);
```

### delete(Integer id)

Deletes the product custom field.

```java
int id = 18;  

pcfService.delete(id);
```

### paginate(SearchProductCustomFieldsRequest request)

Goes through all pages of the search product custom fields response and returns a list with all possible product custom fields that satisfy the request. Makes multiple requests to the server until all results have been found.

```java
SearchProductCustomFieldsRequest request = SearchProductCustomFieldsRequest.builder()  
        .limit(10)  
        .product(1234567891011121L)
        .build();  
  
List<BackOfficeProductCustomField> result = orderService.productCustomFieldsService().paginate(request);
```


[title] Java Hardware (Device) IDs
[path] SDKs/Java SDK/

## Introduction

LicenseSpring SDK already provides some preconfigured identity providers, which are described in the section below. If none of the preconfigured Identity providers match desired use case, feel free to make your own implementation of `IdentityProvider` interface which generates a custom `HardwareId`.

## Getting Started

You can find all preconfigured Identity Providers in module LicenseSpring Core, package

`com.licensespring.model` as Enum `HardwareIdStrategy`.

## Types of Identity Providers

Algorithms 7-12 are provided by the externally loaded LicenseSpring Hardware ID Generator library added in SDK v2.25.0. See [**Hardware ID generation**](docId\:yFnuCniXYZAno8e-sY5I1) for their descriptions.

### 1. AUTO\_HARDWARE\_ID

This identity provider will generate unique Identity key per device. That means that each device you are using will have its own unique identity.

Identity key is generated based on following 3 hardware components:

1. Motherboard
2. Processor (CPU)
3. Hard disks or similar storage units

Use this strategy if you want to generate one and only one unique ID per device and you are running LicenseSpring on physical computer as opposed to running LicenseSpring on Virtual Machine.

### 2. NO\_DISK\_HARDWARE\_ID

This identity provider is the same as `AUTO_HARDWARE_ID`, but without disk information. This in in the cases where users add removable storage devices (like smart card reader) and the hardware ID changes.

### 3. AWS\_NODE\_LOCK

This identity provider will generate unique ID per Virtual machine running on AWS cloud platform. It will generate unique ID by using Virtual machine ID that is unique for each Virtual machine instance. In order to use this strategy, device which is running LicenseSpring must have Internet access as well as access to IP address 169.254.169.254. This is necessary because in order to retrieve VM ID, Metadata service API running on 169.254.169.254 must be called.

Use this strategy if you are running LicenseSpring on AWS cloud platform and want to generate one and only one unique ID per VM instance.

:::hint{type="danger"}
If using this identity provider you must be sure that LicenseSpring application will be running on AWS cloud platform. This is necessary because in case you are trying to use this identity provider on physical computer then `NotCloudPlatformException` will be thrown. Also, in case you are trying to use this on Virtual machine that is not running on AWS, `WrongPlatformException` will be thrown. Unless you are absolutely certain that LicenseSpring will be running on AWS, this strategy should be replaced with `AUTO_NODE_LOCK`.
:::

### 4. AZURE\_NODE\_LOCK

This identity provider will generate unique ID per Virtual machine running on Azure cloud platform. It will generate unique ID by using Virtual machine ID that is unique for each Virtual machine instance. In order to use this strategy, device which is running LicenseSpring must have Internet access as well as access to IP address 169.254.169.254. This is necessary because in order to retrieve VM ID, Metadata service API running on 169.254.169.254 must be called. It Also checks for the `WEBSITE_INSTANCE_ID` environment variable from version 2.4.7 (from version 2.5.2 in `AUTO_NODE_LOCK` too).

Use this strategy if you are running LicenseSpring on Azure cloud platform and want to generate one and only one unique ID per VM instance.

:::hint{type="danger"}
If using this identity provider you must be sure that LicenseSpring application will be running on Azure cloud platform. This is necessary because in case you are trying to use this identity provider on physical computer then `NotCloudPlatformException` will be thrown. Also, in case you are trying to use this on Virtual machine that is not running on Azure, `WrongPlatformException` will be thrown. Unless you are absolutely certain that LicenseSpring will be running on Azure, this strategy should be replaced with `AUTO_NODE_LOCK`.
:::

### 5. AUTO\_NODE\_LOCK

This identity provider will attempt to figure out on which type of device you are running LicenseSpring (physical computer or virtual machine). If you are running on physical device then `AUTO_HARDWARE_ID` strategy will be chosen. If you are running on virtual machine then, depending on which cloud platform you are running LIcenseSpring, either `AWS_NODE_LOCK` or `AZURE_NODE_LOCK` strategy will be chosen.

Use this strategy if you are not sure on what type of device LicenseSpring will be running.

:::hint{type="danger"}
`AUTO_NODE_LOCK` strategy will not throw Exceptions like `AWS_NODE_LOCK` or `AZURE_NODE_LOCK` do. But because `AUTO_NODE_LOCK` needs to figure out which strategy to choose, it takes longer to execute.
:::

### 6. ONCE\_PER\_PROCESS

This identity provider will generate new identity each time method `getKey()` is called. This is useful for generating multiple identity keys on one device. This strategy is useful for floating license as identity key is not bound to single hardware/device - so that multiple processes/VMs (or several layers of VMs) will have unique keys - preventing over-usage.

This is the default method used by the [**Floating Client**](docId:85OZDMi_CEEi_i5T6ldh7). Use this strategy in order to completely control how many instances of your application are running. It also requires the `cacheHardwareID(boolean)` configuration option to be `true` or a `ConfigurationException` will be thrown during init.

### 7. DEFAULT

### 8. WINDOWS\_HARDWARE\_FINGERPRINT\_ID

### 9. WINDOWS\_COMPUTER\_SYSTEM\_PRODUCT\_ID

### 10. WINDOWS\_CRYPTOGRAPHY\_ID

### 11. LINUX\_MACHINE\_ID

### 12. CLOUD\_PLATFORMS\_ID

### 13. Custom identity provider

If none of identity providers matches your use case, feel free to make your own custom implementation. `IdentityProvider` interface can be implemented in the following way:

```java
public class MyCustomIdentityProvider implements IdentityProvider {
    @Override
    public String getKey() {
        return "myCustomIdentityKey";
    }
}
```


[title] Tutorials
[path] SDKs/

Welcome to LicenseSpring Tutorials, your gateway to understanding the basics of implementing a powerful and efficient software licensing solution.&#x20;

Whether you're a seasoned software developer, an independent software vendor, or an enterprise seeking to safeguard and monetize your applications, LicenseSpring is here to meet your needs.

Throughout these comprehensive tutorials, we will guide you step-by-step through the seamless integration of LicenseSpring into your software product, unleashing the full potential of your licensing strategy.

Embark on this enlightening journey as we equip you with the essential knowledge and tools to optimize your software licensing strategy, propelling your business to new heights!

[title] Java SDK
[path] SDKs/

The [**Java License Client**](docId\:UwqR7jQG01pCftet8Iao0) module embodies essential license functionalities, encompassing tasks like online and offline license activation and deactivation, provisioning trial licenses, recording usage instances, and monitoring variables.

The [**Floating Client**](docId:85OZDMi_CEEi_i5T6ldh7) serves as the foundational module with a specific emphasis on floating license functionalities. For a deeper understanding of floating licenses, additional information can be accessed by referring to the provided resource on [**Floating Licenses**](docId:4aUNyPIaL8I2te4NypPx7).

The [**Management SDK**](docId\:oqeHm3FlI2mJ-0AQ8u724) module offers a collection of APIs designed to generate license keys and facilitate order placement. For further details about the general Management API, see our [**Management API**](docId\:abk8afS7gBMtujL_Rd_4p).

:::hint{type="danger"}
Minimum Java version for this SDK is 8.161.
:::

:::hint{type="info"}
If you are unsure which SDK module to implement, visit [**Java Modules**](docId:-6YDRWccXDNLN9Fw4ZYa4) to learn what each module offers.
:::

:::hint{type="info"}
From version 2.2.0 onwards, you can find all the release artifacts - direct downloads, including hosted Javadoc links on our [**Javadoc & Downloads**](docId\:Dm-Ksn9S-VVHGLpYWSm5x) page.
:::

## Release Notes

## February 10th, 2026, v2.27.0

### License Client:

- **New:** Added fields to LicenseData: isLicensed, isValid, isExpired, licenseActive, licenseEnabled, floatingInUseDevices, maxLicenseUsers, signature, startDate, trialDays, policyId, and others

### Floating Client:

- **New:** Added support for Floating Server v2.2.0 (except license bundles)
- Updated [**Floating Server V2**](docId:3EG92A6TMN_Hi0Ddt9WE3) with full API reference including getLicenseUsers(), getLicenseFeatures(), offline/airgap methods, configuration endpoints, and typical integration flow

## February 3rd, 2026, v2.26.2

### License Client:

- Add schema v2 support for offline deactivation request (activation request already has it)

## December 9th, 2025, v2.26.1

### License Client:

- **Fix:** Character encoding issue in offline license signature verification
  - Fixed `String.getBytes()` call in `AuthorizationService.checkSignature()` to explicitly use UTF-8 encoding
  - Previously, signature verification would fail when JVM default charset was not UTF-8 (e.g., `windows-1250`) and license contained non-ASCII characters (e.g., customer
    names like "József", "Pelikán")
- **New:** Added `NoDelete` variants for offline deactivation methods
  - `offlineDeactivationFileNoDelete(License license, String destination)` - generates deactivation file without clearing local license storage
  - `offlineDeactivationStreamNoDelete(License license, OutputStream outputStream)` - writes deactivation request to stream without clearing local license storage
  - Use these methods when you need to ensure the deactivation data is safely persisted before clearing the license, then call `clearLocalStorage()` manually

### Floating Client:

- **Fix:** Connection leak in `ProxyFloatingService`
  - Fixed response body not being closed in `serverHealthy()`, `setPassword()`, `setKeys()`, and `unregisterAll()` methods
  - This was causing OkHttp warnings: "A connection was leaked. Did you forget to close a response body?"

## December 2nd, 2025, v2.26.0

### License Client:

- Added `encryptionKey` configuration parameter to `LicenseSpringConfiguration`
  - Allows setting a custom, stable encryption key for local license file (`license.key`) encryption
  - Decouples license file encryption from authentication credentials (sharedKey/clientSecret)
  - Useful when using OAuth authentication where the clientSecret may rotate
- Added automatic migration support in `EncryptedFileLicenseRepository`
  - On load, if decryption with the primary key fails, the SDK will attempt to decrypt using fallback keys (sharedKey, clientSecret)
  - If successful, the license is automatically re-saved with the new encryption key

### Migration Guide

To migrate from clientSecret-based encryption to a stable encryptionKey:

1. Configure both the current `clientSecret` and the new `encryptionKey`:

```java
LicenseSpringConfiguration config = LicenseSpringConfiguration.builder()
    .clientId("your-client-id")
    .clientSecret("current-client-secret")
    .productCode("PRODUCT")
    .encryptionKey("your-stable-encryption-key")
    .build();
```

2. On first load(), the SDK will:
   - Try to decrypt with encryptionKey (fails for existing files)
   - Fall back to clientSecret (succeeds)
   - Automatically re-save the license encrypted with encryptionKey
3. Future OAuth secret rotations will not affect the license file encryption.

***

## November 19th, 2025, v2.25.2

**All:**

- Added **floatingInUseDevices&#x20;**&#x61;nd **floatingInUse&#x20;**&#x74;o **LicenseFeature** (used with floating server)

**Floating Client:**

- Changed signature verification to use decoder instead of interceptor for floating v2 api (was consuming body stream too early, causing problems with other interceptors)

**All:**

- Fix issue with encoding non-ASCII characters in Offline file

## October 27th, 2025, v2.25.0

**All:**

- Add new Hardware ID Algorithms:
  - `DEFAULT`
  - `WINDOWS_HARDWARE_FINGERPRINT_ID`
  - `WINDOWS_COMPUTER_SYSTEM_PRODUCT_ID`
  - `WINDOWS_CRYPTOGRAPHY_ID`
  - `LINUX_MACHINE_ID`
  - `CLOUD_PLATFORMS_ID`

## October 6th, 2025, v2.24.1

**All:**

- Fix Signature encoding in Offline License File V2

## September 19th, 2025, v2.24.0

**All:**

- Offline License File V2 - new JSON schema

## September 16th, 2025, v2.23.1

**All:**

- null check on License Consumptions - for licenses without negative consumptions or unlimited consumptions configured

## September 15th, 2025, v2.23.0

**All:**

- null check on License Feature Consumptions - for legacy license features without negative consumptions or unlimited consumptions configured

## August 26th, 2025, v2.22.0

- **DEPRECATION:**
  - **LicenseService**
    - **deactivateOffline(LicenseIdentity identity)**
    - **deactivateLicenseOffline(LicenseIdentity identity)**
  - **LicenseManager**
    - **offlineDeactivationFile(LicenseIdentity identity, String destination)**
    - **offlineDeactivationStream(LicenseIdentity identity, OutputStream)**
    - **deactivateLicenseOffline(LicenseIdentity identity)**
- All Deprecated methods have been replaced with equivalent method that uses **License&#x20;**&#x70;arameter instead of **LicenseIdentity&#x20;**&#x70;arameter

## July 24th, 2025, v2.21.1

**License Client:**

- added licenseData.getCompany.getId() field
- AUTO\_NODE\_LOCK max time to execute 1,5sec (removed default retry)

## July 11th, 2025, v2.21.0

**Floating Client:**

- Experimental Floating Server v2 Support
- Added methods to ProxyFloatingService to support Floating Server v2:
  - getLicenses
  - changePassword
  - borrowLicenseV2
  - registerUserToLicenseV2
  - unregisterUserFromLicenseV2
  - registerFeatureForUserV2
  - unregisterFeatureForUserV2
  - addConsumptionToLicenseV2
  - addConsumptionToFeatureV2
  - addLicenseV2
  - getLicenseById
  - removeLicenseById
  - addUser
  - removeUser
  - login

## July 7th, 2025, v2.20.5

**License Client:**

- Base64Codec.decode now trims whitespace before decoding (to resolve issues in existing CI/CD systems)

## June 9th, 2025, v2.20.4

**License Client:**

- in `LicenseManager.checkLicense()` -> rethrow LicenseSpringException types and their subtypes (fix for `gracePeriodDays` and `ignoreServerExceptions` config params)

## May 20th, 2025, v2.20.3

**License Client:**

- changed the default `EncryptedFileLicenseRepository` to save the license file only if fully written

## May 13th, 2025, v2.20.1

**License Client:**

- updated offline requests to use updated OAuthCredentials (instead of the unchanged config ones)

## May 12th, 2025, v2.19.2

**License Client:**

- added `LicenseManager.getOAuthCredentials` method to check the current OAuth client id and secret used (since config is a final class with final fields -> updating oauth credentials doesn't update the initial config)

## May 12th, 2025, v2.19.1

**License Client:**

- Added `LicenseManager.getOfflineLicenseContent` to get the response from the activate offline endpoints [**Activate License (Offline Method)**](docId\:H_VEWmE7rYJ7QfbIKvGuP)

## May 9th, 2025, v2.19.0

**License Client:**

- added `LicenseManager.changeOAuthCredentials` method
- added activate `LicenseManager.activateLicenseOffline` and `LicenseManager.deactivateLicenseOffline` methods
  - should be used for TESTING PURPOSES only
  - api references: [**Activate License (Offline Method)**](docId\:H_VEWmE7rYJ7QfbIKvGuP), [**Deactivate License (Offline Method)**](docId\:iyg1DXIYqp9vW-Mlj-xUk)
- added `LicenseManager.updateFromOfflineResponse` method for updating offline licences

**Floating Client:**

- added support for [**Floating Features**](docId\:fcSUKwoO8k2E5oNfqFtRo)&#x20;

**All:**

- added `LicenseData.isBorrowed` and `LicenseData.borrowedUntil` fields
- added `LicenseFeature.allowNegativeConsumptions` field
- changed checking of `allowNegativeConsumptions` **to license and feature settings instead of sdk config**, deprecated config param

## May 6th, 2025, v2.18.5

**License Client & Floating Client:**

- `serviceUrlCertPath` can be a resource as well (or a file)

## May 6th, 2025, v2.18.4

**All:**

- added new util class in licensespring-core: Base64Codec - handles base64 related operations and ensures correct padding

## April 30th, 2025, v2.18.3

**License Client & Floating Client:**

- fixed a bug regarding the new `serviceUrlCertPath` configuration option

## April 30th, 2025, v2.18.2

**License Client**

- added `serviceUrlCertPath` configuration option when (goes with custom serviceUrl for verification purposes) - see [**Java Advanced Usage**](docId\:mqLRngvkrEpJ5IVdGUpt0) **\*BUG WHEN USING THIS FEATURE, UPGRADE TO 2.81.3 OR NEWER TO USE IT\***
- added `License.isOfflineActivated` - when the license was activated offline or using air-gapped
- fixed offline licensing support when using OAuth
- updated offline activation - added support for variables and tracking machine info (if enabled in config)
- updated consumption sync:
  - syncs features for all license types if the features have consumtions
  - added unlimited consumptions support (feature and license)
- Added `LicenseData.allowUnlimitedActivations`

**Floating Client:**

- added `serviceUrlCertPath` configuration option when (goes with custom serviceUrl for verification purposes) - see [**Java Advanced Usage**](docId\:mqLRngvkrEpJ5IVdGUpt0) **\*BUG WHEN USING THIS FEATURE, UPGRADE TO 2.81.3 OR NEWER TO USE IT\***

## April 17th, 2025, v2.18.1

**License Client:**

- licenseManager.activateLicense() - removed existing license modification when activating another license (like deleting in case the new license is not found)

## April 4th, 2025, v2.18.0

**Management Client:**

- Added metadata filtering capability to Management SDK
  Implemented metadata filtering for:

  - getLicenses
  - getLicenseProductFeatures
  - getOrders
  - getProducts

**License Client:**

- Added optional env query parameter to:
  - checkLicense
  - getProductDetails
  - getVersions
  - getInstallationFile
- Added optional licenseId param for users with multiple licences
- added \`userLicenses\` and \`deviceLicenses\` endpoints

**Floating Client:**

- Updated ProxyService to support the following floating server API methods:
  - setPassword
  - setKeys
  - serverHealthy
  - getLicense
  - addLicense
  - removeLicense
  - generateAirgapSignature
  - registerUser
  - unregisterUser
  - unregisterAllUsers
  - addConsumption
  - addFeatureConsumption

## March 3rd, 2025, v2.17.1

**License Client & Floating Client:**

- Added [**OAuth Authorization**](docId\:xhYZAUaL9QY4jerxKilmk) support by setting `clientId` and `clientSecret` in the Floating or LicenseSpring Configuration. Check out [**OAuth Configuration**](docId\:q1YECed3KGhZMwcSX2MOJ) on how to setup. For rotating secrets, there is a changeOAuthClientSecret method in LicenseManager of FloatingLicenseService.

## February 12th, 2025, v2.17.0

**All:**

- Updated LicenseSpring sdk license and added dependancy licences to the .jar. More info here: [**SDK Distribution and Licensing**](docId\:PiTcNTyYaJV9nsyuYOEZA)&#x20;

**License Client:**

- added `LicenseManager.getSsoUrl`
- added `LicenseManager.getAirGapDeactivationCode` and `LicenseManager.deactivateAirGapResponse`

**Management Client:**

- supports java 16+ (LocalDateAdapter)

## December 30th, 2024, v2.16.6

**License Client**:

- add `LicenseNotFoundException` and `LicenseNotEnabledException` for the appropriate license statuses
- `manager.checkLicense` will throw the appropriate exception and update the local license

## November 20th, 2024, v2.16.5

**License Client**:

- properly passed down LicenseRepository to LicenseService

## October 24th, 2024, v2.16.4

**All**:

- update `com.google.code.gson` to 2.11.0

**Floating Client:**

- added support for user based licences on borrowLicense method

## August 27th, 2024, v2.16.3

**License Client**:

- added missing customer fields (12 up from 7)

**Management Client:**

- remove orderBy `active_up_to_date_devices` - not supported anymore

## July 25th, 2024, v2.16.2

**Floating Client:**

- ProxyFloatingService.register() method should parse responses from newer floating-server versions (backwards compatible)

## June 26th, 2024, v2.16.1

**All:**

- update oshi version to 6.6.0

**License Client**:

- added configuration options to force signature v2 check

**Management Client:**

- added the following:
  - **LicenseService.updateFeatures**
  - **LicenseService.deleteLicense**
  - **OrderService.safeDeleteOrder**
- updated response type in **LicenseService.createOrder**

## May 29th, 2024, v2.16.0

**All**:

- Added **JsonElement metadata** field to: LicenseData, Customer, Product, LicenseFeature (licenseclient sdk and management sdk)
- Added **LicenseManager.getDeviceVariables(identity)**
- Added a parameter to the **LicenseManager.initialize()** method to accept **OkHttpClient.Builder** for customization of the underlying client (for a https proxy use case)

**Breaking Change:**

- **metadata&#x20;**&#x66;ield in LicenseFeature model changed from **Object** type to **JsonElement**

## May 7th, 2024, v2.15.0

**All**:

- Added **LicenseUser** model and **user** field in **LicenseData&#x20;**&#x66;or user based licenses
- Added expiration check on **getCurrent()** calls while in offline mode
- Added fallback when detecting OS version

## April 16th, 2024, v2.14.0

**All**:

- Add **VerifySignatureDecoder** to enhance security by verifying signatures of server responses
- Set **active** and **enabled** fields to true after successfully performing local check
- Bump **org.bouncycastle.bcpkix-jdk18on, org.bouncycastle.bcprov-jdk18on&#x20;**&#x74;o **v1.78**
- Enhance license security by storing the **LicenseData** signature alongside the license file and conducting **signature verification upon loading the license** from the file

## January 19th, 2024, v2.13.0

**All**:

- Bump io.github.openfeign v12.4 -> v13.1
- Change scheduler mode to fixed-rate

**License Client**:

- Add CachedEncryptedLicenseRepository that caches license in-memory

## December 12th, 2023, v2.12.0

**Floating Client**:

- **FloatingLicenseService**:
  - Add **releaseFloatingFeature**
  - Add **checkLicenseFeature**

**License Client**:

- **LicenseService**:
  - Add **checkLicenseFeature**

**Management Client**:

- **FloatingFeaturesService**:
  - Add **releaseDevice**
  - Add **getLicenseProductFeature**
  - Add **getLicenseProductFeatures**
  - Add **updateFeatures**

## December 6th, 2023, v2.11.1

All

- **Compatibility with older Java versions:&#x20;**
  - **v1.8u141 and older**: Trust LicenseSpring API Root certificate
  - **v1.8u161 and older**: Fallback to 128 bit key size because key size greater than 128 bit is not supported.
- **Deprecate disableSSL option**

## November 7th, 2023, v2.10.0

All

- **Proxy Certificate:&#x20;**&#x55;sers can provide .pem file certificate in order to configure HTTP client to trust Proxy Server certificate.
- **Connection Specs:&#x20;**&#x55;sers can provide connection specs to setup HTTP client with different cipher suites.

## October 12th, 2023, v2.9.0

Floating Client

- added Floating License borrowing

## September 14th, 2023, v2.8.6

All SDK's

- added `resetConsumption` and `consumptionPeriod` to `LicenseFeature` class

## July 10th, 2023, v2.8.3

All SDK's

- Changed the exception message (`ConnectionException`) when there are problems with proxy auth. New message is:
  - "Failed to authenticate with the proxy server. Please check your proxy credentials setup or contact your IT department for assistance."

## July 3rd, 2023, v2.8.2

All SDK's

- Added `id` and `deviceId` fields to the `LicenseData` class

## June 26th, 2023, v2.8.1

License Management

- Fix error decoder empty code and message fields

## April 28th, 2023, v2.8.0

License Management

- BREAKING: Changed single user to list of users in `OrderLicense` class
- Added `isManager` boolean field to `UserBasedLicense` class

## April 28th, 2023, v2.7.0

All SDK's

- Add support for parsing date when creating `ZonedDateTime` `License Client`
- Fixed `AirGapped` signatures

## March 17th, 2023, v2.6.2

Floating Client

- Fix when using only `checkLicense()` (without `activateLicense()` - example: on app restart)

## March 1st, 2023, v2.6.1

License Client

- Changed `AirGapped` to use Java classes instead of `BouncyCastle`

## February 28th, 2023, v2.6.0

All SDK's

- `licenseSignature` verification fix (pem files)

## January 30th, 2023, v2.5.9 - **BROKEN VERSION**

License Client

- Remove unused `BouncyCastle` provider in `AirGappedService`

## January 17th, 2023, v2.5.8 - **BROKEN VERSION**

License Client

- Renewed the code signing certificate

## January 16th, 2023, v2.5.7 - **BROKEN VERSION**

License Client

- Removed `BouncyCastle` provider for `AirGap` - use default provider

## January 10th, 2023, v2.5.6 - **BROKEN VERSION**

License Client

- Added support for multiple licenses on the same device. Added the `LicenseManagerFactory` for creating multiple `LicenseManager` objects (one for each different license)
- Added support for offline user-based licences


## November 4th, 2022, v2.5.5 - **BROKEN VERSION**

License Client

- Added `AirGappedService` and `LicenseSpringManager` methods: `getAirGapActivationCode()`, `verifyAirGapConfirmationCode()`, `activateAirGapResponse()`

## August 10th, 2022, v2.5.4

License Client

- Added `reinitialize()` methods to `LicenseManager`

## June 28th, 2022, v2.5.3

All SDK's

- Corrected query parameters on azure metadata endpoint

## June 10th, 2022, v2.5.2

All SDK's

- Added azure environment variable `WEBSITE_INSTANCE_ID` check to `HardwareIdStrategy.AUTO_NODE_LOCK`

## May 18th, 2022, v2.5.1

All SDK's

- Updated OSHI library to 6.1.6 version

## December 21st, 2021, v2.5.0

License Client and Floating Client

- Added verification on any kind of license load.

## December 20th, 2021, v2.4.16

License Client and Floating Client

- Added verification of license on every check call.

## December 14th, 2021, v2.4.15

All SDK's

- Added `HardwareIdStrategy.NO_DISK_HARDWARE_ID`, for creating hardware IDs without disk information (in case of removable card readers or similar devices that are detected as disks). For more information, see [**Java Hardware (Device) IDs**](docId\:KinnDEO4BgHcV3azYvchM)

## December 9th, 2021, v2.4.14

License Client

- Added `setOfflineMode` to `LicenseManager`.

License Client and Floating Client

- Added `infoToStore` configuration parameters. This enables to fine tune what information you want to send to LS servers during license activation and checking. If `storeMachineInfo` is off, then this property is ignored, defaults to ALL info. Docs are at the end of configuration optional parameters, see [**Java License Client**](docId\:UwqR7jQG01pCftet8Iao0) for an example for `License Client`

## November 22nd, 2021, v2.4.13

- Populated `lastUsage` field after license check (resolves issues when using offline mode after online activation)
- Added `storeMachineInfo` configuration parameter (`License` and Floating Configurations) - false by default. This toggles the collection of additional machine data, which includes:
  - `hostname`
  - `ipAddress`
  - `macAddress`
  - `vmInfo`
  - `osInfo`

## November 10th, 2021, v2.4.12

All SDK's

- Added `requestTimeout` to configurations (in seconds) for API calls, defaults to 10 seconds

## October 11th, 2021, v2.4.11

License Client

- Added fields to `LicenseFeature` class: `allowOverages`, `maxOverages`
- Added overages logic to `increaseConsumption()` and `increaseFeatureConsumption()` methods

## September 29th, 2021, v2.4.10

Management SDK

- Added fields to `ProductFeature` class: `allowOverages`, `maxOverages`, `resetConsumption`, `consumptionPeriod`


## August 27th, 2021, v2.4.9

All SDK's

- Added azure environment variable check (`WEBSITE_INSTANCE_ID`) for offline azure cloud instances
- Added `name` and `expiryDate` for `LicenseFeatures`

## June 29th, 2021, v2.4.8

All SDK's

- Added `shutdownScheduler()` method to client SDKs for manually shutting down the scheduled executors used for periodic checks, see [**Java Advanced Usage**](docId\:mqLRngvkrEpJ5IVdGUpt0).

## June 24th, 2021, v2.4.7

All SDK's

- Added `Shutdown` hooks to all executor services (used when the periodic check feature is turned on)
- Added the `disableSsl` configuration option for rare cases when the app cannot verify LicenseSpring servers certificates. More info in [**Java Advanced Usage**](docId\:mqLRngvkrEpJ5IVdGUpt0).

## June 9th, 2021, v2.4.6

All SDK's

- Added support for basic authentication when using a forward proxy. Just set `proxyUser` and `proxyPass` in any configuration object to use. More info in [**Java Advanced Usage**](docId\:mqLRngvkrEpJ5IVdGUpt0).

## May 20th, 2021, v2.4.5

All SDK's

- Added support for AWS IMDSv2 node locking (was only IMDSv1)
- Additional fields to the `LicenseData` object:
  - `allowOverages`
  - `maxOverages`
  - `preventVm`
  - `isFloatingCloud`
  - `isFloating`
  - `transferCount`
  - `floatingInUseDevices`
  - `floatingInUse`
  - `resetConsumption`
  - `consumptionPeriod`

You can read the description of each field in the [**Javadoc & Downloads**](docId\:Dm-Ksn9S-VVHGLpYWSm5x) section.

Floating Client SDK

- Added on-premise floating server support! Documentation can be found on our [**Proxy Floating**](docId:-r7g0sf5yq0jYyawahn_9) page.

Management SDK

- Added `licenseUsers` to the `DeviceLicense` object (used in the devices via `LicenseServices`)

## April 19th, 2021, v2.4.4

License Client

- Added `ignoreServerExceptions` field in `LicenseSpringConfiguration` - when enabled, it acts as `gracePeriodDays` (ignoring exceptions if SDK cannot connect to LS servers for `License` check), but without a time limit

## April 15th, 2021, v2.4.3

License Client

- Increased the maximum allowed for `gracePeriodDays` to 30 (was 5) and added that information to [**Java License Client**](docId\:UwqR7jQG01pCftet8Iao0)

## April 13th, 2021, v2.4.2

All SDK's

- Added `Locale.ENGLISH` for query field name serialization (fix for Turkish locale)

Management SDK

- Changed field in the `Device` model - "license" is no longer just an ID, now it's an object with: `id`, `license_key`

## April 9th, 2021, v2.4.1

License Client

- Fixed an issue when in offline mode to check for clock tampering before setting the `lastUsage` (this is done during initialisation and on every `LicenseManager.getCurrent()` call) - you can also manually check for clock tampering in by calling `license.localCheck()`

## April 2nd, 2021, v2.4.0

This release introduces a multitude of changes made in the License Management module. A lot of DTO changes (request and response models). If you are using the **License Management&#x20;**&#x53;DK, please update to the latest version since older API's are no longer supported or they had method signature changes.

### BREAKING CHANGES

Management SDK

- Removed `assignUsers` method in `OrderService`. There is a new method with similar functionality in `LicenseService` called [**Management SDK**](docId\:oqeHm3FlI2mJ-0AQ8u724)
- The field `orderItems` in the search result of `searchOrders` method is now empty to cut down on length of the results. The field `orderItems` is still available for reading while using the `getOrder` method.
- `BackOfficeLicense` has a field product which isn't Long type anymore, instead it's a class `BackOfficeLicenseProduct`.
- Removed fields `companyName` and reference from `LicenseUser` class.
- Removed field `companyName` from `AssignUserToLicenseRequest` class.

Floating Client SDK

- Removed field `isCloudFloating` from `FloatingConfiguration` class. The field is redunant because floating/floating cloud configurations are separated in two classes: `ProxyConfiguration` and `FloatingConfiguration`.

### Changelog

All SDK's

- Added support for a forward proxy! Just set `proxyPort` and `proxyHost` in any configuration object to use the forward proxy. More info in [**Java Advanced Usage**](docId\:mqLRngvkrEpJ5IVdGUpt0)
- Updated oshi and feign libraries to their latest versions (5.6.1 and 11.1) - to fix some bugs on Windows

License Client

- Added deletion of local license file in `checkLicense()` method (invoked during initialisation too), in case of `license_not_found` response (this is the case of deleting a license)

Management SDK&#x20;

- 3 new services added as a composition to existing management services:
  - `DeviceVariablesService` found in `LicenseService`&#x20;
  - `LicenseCustomFieldsService` found in `LicenseService`
  - `ProductCustomFieldsService` found in `OrderService`&#x20;
- All 3 (`DeviceVariablesService`, `LicenseCustomFieldsService`, `ProductCustomFieldsService`) have the following methods:
  - `search`
  - `get`
  - `create`
  - `update`
  - `delete`
  - `paginate`
- Added `enableRetrying` option to `ManagementConfiguration` (same functionality as in the other SDKs)
- New method `setUserPassword` in `LicenseService` class.
- Added prebuild check for `releaseDate` field in `CreateInstallationFileRequest` to check if it's in YYYY-MM-DD format.
- New fields in `BackOfficeCustomer` class :
  - `labels` - array of customers labels
  - `allLabelNames` - name of customers labels
  - `labelIds` - ids of customers labels
- New fields in `BackOfficeLicense` class:
  - `licenseUsers` - list of all users that use the license
  - `activeUpToDateDevices` - total number of devices that are currently using the license
  - `totalActiveDevices` - total number of devices that have status active on the license
  - `note` - note about the license
  - `maxLicenseUsers` - maximum number of users that can use the license
- New fields in `LicenseUser` class:
  - `isStaff` - boolean, is user also a part of the company staff
  - `subscribedToEmail` - boolean, is user subscribed to newsletter
  - `acquiredConsent` - date when consent was acquired
- New field in `AssignUserToLicenseRequest` class, `isManager` boolean field.
- New methods in `LicenseService` class:
  - `resetTotalConsumptions`
  - `setTotalConsumptions`
  - `assignMultipleUsers`
  - `unassignUser`
  - `blacklistDevice`
  - `resetDevice`
- New methods in `OrderService` class:
  - `searchInstallationFiles`
  - `getInstallationFile`
  - `createInstallationFile`
  - `paginateThroughAllInstallationFiles`
- New filters and sort options in search requests.

## September 25th, 2020, v.2.3.2

- Adapted the caching mechanism in the `License` class, so that both feature and license consumptions are first checked and then updated. (apriori)

## September 22nd, 2020, v.2.3.1

- Fixed issue with license feature consumption
- Added utility methods to check presence of features on `LicenseData` class
- Fixed wrong javadoc on the `LicenseManager` class, check method. Added more context for check method.

## September 18th, 2020, v.2.3.0

Online documentation

- Added Javadoc coverage information on online documentation per module & version
- Added a help page on [**Java Modules**](docId:-6YDRWccXDNLN9Fw4ZYa4)

License Client

- Added offline de/activation methods with `InputStream` and `OutputStream` as parameters
- Fixed issue with offline activation response loading - wrong file name.

LicenseManager

- Added `patchLicense` method to modify product features on existing licenses.
- Added some javadoc
- Increased test coverage

## September 10th, 2020, v2.2.0

Core SDK

- Completely restructured online documentation
- Transitions to hosted [**Javadoc & Downloads**](docId\:Dm-Ksn9S-VVHGLpYWSm5x). The javadoc is still available for download via maven.
- Added node locking options for AWS and Azure Cloud(s)
- Refactored internal class packages
- Added a `Retryer` option, which enables retries of failed requests due to infrastructural reasons (connection issues, server 5xx errors) - up to 4 retries with the longest delay period of 20 seconds. Off by default.
- Expanded the `LicenseSpring Exception` model (note: the basic classes still remain, all extend from `LicenseSpringException`, and are still unchecked)
- Rewritten `@SuperBuilder` in configuration classes, to generate javadoc properly
- Added a delombok process, in order to add javadoc to auto-generated code
- Higher coverage with javadoc on all Java SDKs

License Client SDK

- Added a grace period configuration option, which resolves the remote `Check` services to a local license check with a grace period from 1 to 5 days. Note that the grace period applies only to the `Check` method and for infrastructural problems (connection, server error). License validation exceptions are still thrown. Default behaviour is off.
- Added throws `LicenseSpringException` to every `LicenseManager` method (unchecked)
- Enabled negative increments of consumptions - defaults to disabled in configuration.
- Removed the option to place orders from the Client SDKs.

Floating Client SDK

- Implemented an automated `Shutdown` hook background thread. The thread releases activated licenses and deactivates the license. By default the shutdown hook is enabled, and can be disabled
- Added a per-process (UUID) generated hardware ID strategy which works well with the floating license model.
- Defined a `CheckSubscriber` interface which can be used to subscribe to background check events. Default implementation ignores the incoming events.
- Added a background periodic check caller for all activated licenses. Deactivation removes the licenses from the pool. Period is 1/2 of the floating license duration. On by default.
- Tested support for multiple licenses and products at the same time. Multiple `FloatingLicenseServices` required for multiple products, multiple licenses on the same product can be used within the same `FloatingLicenseServices` instance.

Management SDK

- Implemented the following methods on `LicenseService`
  - `searchLicenses`
  - `disableAllLicenses`
  - `disableLicense`
  - `getLicense`
  - `updateLicense`
  - `assignUser`
  - `resetLicense`
  - `enableLicense`
  - `searchDevices`
  - `getDevice`
  - `paginateThroughAllLicenses`
  - `paginateThroughAllDevices`

Implemented the following methods on `OrderService`

- `searchOrders`
- `getOrder`
- `exportToCsv`
- `assignUsers`
- `generateLicenseKeys` (migrated from Webhook API)
- `createOrder` (migrated from Webhook API)
- `searchProducts`
- `getProduct`
- `paginateThroughAllOrders`
- `paginateThroughAllProducts`

## July 28th, 2020, v2.1.0

- Added OSGi support

## July 15th, 2020, v2.0.2

- Removed oshi-demo from dependancy list
- Support in detecting AWS EC2 instances
- Added javadoc in `Floating SDK`

## July 15th, 2020, v2.0.0

- Java SDK was split into 4 different modules
- Manifest updated and created for each module - support for OSGI was added
- Added LICENSE file to distribution in jars
- Added support for floating licenses

Auto-Generated javadoc on deployment - ready for use in iDEs.

## June 12th, 2020, v1.9.3

- Refactored offline license request/response code from `LicenseRepository` into a separate class
- Made `LicenseRepository` an interface SDK users can implement.
- Added a `intitialize()` method overload on `LicenseSpringManager` which accepts the `LicenseRepository` as the second parameter.
- Added the default implementation of `LicenseRepository`, no SDK users will not need to change their implementation, unless building a custom `LicenseRepository`.
- Added some checks to prevent entering locking code when there is no need to sync consumptions with LicenseSpring servers.

## May 22nd, 2020, v1.9.2

- Fixed issues with consumptions and caching - the local consumption check was not performed with local state.
- Removed license deletion on initialization because of server errors. The SDK still deletes the license if the hardware key does not match the one in the license file. The `LicenseManager initialize()` method can now throw the `LicenseSpringException`, which the client should handle per use case basis.

## May 21st, 2020, v1.9.1

- Fixed bug with `daysRemaining` method on License. SUBSCRIPTION license returned max days, instead of CONSUMPTION type.

## May 8th, 2020, v1.9

- Fixed issues with OSHI auto-update version
- Added request logging options, default is OFF/NONE.
- Added more tests
- Refactored code

## May 1st, 2020, v1.8

- fixed issues with Version API
- implemented local cache for feature consumptions
- added consumption sync to standard check calls
- implemented periodic license check - can be enabled via configuration. Period of sync can also be specified.

## April 2nd, 2020, v1.7

- exposed `JsonSerialization` class

## March 29th, 2020, v1.6.

- Fixed omission of `generateTrialKey` overload with full customer details
- Implemented `Order` model

## March 19th, 2020, v1.4.

- Fixed bug in hardware key generation when no disk is mounted (e.g. VM)

## March 13th, 2020, v1.3

- Added javadoc
- Changed hardware key generation (might break some builds) - reactivate your license.
- Fixed minor issues on tracking OS name
- Fixed major issue with locale support

## February 28, 2020, v0.0.1

- Initial Release of the LicenseSpring Java SDK.
- There are issues with Offline activation, expected to be resolve by 7th of March, 2020.


[title] Analytics
[path] Management API/


[title] List Device Variables
[path] Management API/Device/Device Variables/

Show all device variables the requesting manager has access permissions to.

**URL**: `/api/v1/device-variables/`

**Method**: `GET`

### Query Parameters:

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on product custom field or related to the product custom field.

Possible filters:

- `device`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "count": 3,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 2018,
            "created_at": "2021-02-01T07:24:08Z",
            "variable": "v7",
            "value": "ggg",
            "device": 1112
        },
        ...
    ]
}
```


[title] /activities-hourly/
[path] Management API/Analytics/


[title] Proxy Floating
[path] SDKs/Java SDK/Java Modules/

The `ProxyFloatingService` is intended to be used with the on-premise [**Floating Server**](docId\:uzGCwYdxkClUYUsc1Lcsg)  and is part of the [**Floating Client**](docId:85OZDMi_CEEi_i5T6ldh7) module.

## Initializing the Proxy Floating Client module

At the **minimum** there are **three parameters** you will need to initialize the SDK:

- `apiKey`, your company API key
- `sharedKey`, company-specific encryption key, used when signing requests
- `productCode`, an alphanumeric code identifying a specific product

The `productCode` is tied to a specific product the license applies to and is defined while creating the product.

**Optional** Configuration parameters for initializing the Floating Client SDK:

- `addShutdownHook` indicates if you want the SDK to automatically release any currently active licenses on the device before you shut down the runtime process. Default is true.
- `enablePeriodicRegister` enables periodic calls to register method to prolong the license usage. It will be prolonged every time the license has passed half of its floating timeout time. Usage time is set through the LicenseSpring platform with the `floatingTimeout` parameter in the product configuration
- `proxyRegisterSubscriber` subscriber on periodic register, default implementation is `IgnoreRegisterEventSubscriber`, but you can add your own implementation to handle the `onSuccess` and `onError` of the periodic register. This, of course, isn't a parameter you need to worry about if you chose not to enable periodic checks.
- `requestLogging` request logging for debug purposes, default is no request logging.
- `appVersion` manually set the version of the application that's using the SDK.
- `enableRetrying` enables the retry option on failed API call to the server. The call can be repeated for up to 4 times. Default is false
- `identityProvider` set a custom `IdentityProvider` which generates unique keys for a particular device. Default implementation is based on `ONCE_PER_PROCESS`. More details on our [**Java Hardware (Device) IDs**](docId\:KinnDEO4BgHcV3azYvchM)
- `requestTimeout` set the timeout of requests make to API (in seconds), default is 10 seconds

```java
// configuration with only required parameters
// NOTE building a LicenseSpringConfiguration without required parameters will throw a ConfigurationException
try {
  ProxyConfiguration configuration = ProxyConfiguration.builder()
    .host("localhost")
    .port(8080)
    .product("pc")
    .build();
} catch (ConfigurationException e) {
  log.error(e.getCause().getMessage());
}

// Configuration with more parameters
try {
  ProxyConfiguration configuration = ProxyConfiguration.builder()
    .host("localhost")
    .port(8080)
    .product("pc")
    .addShutdownHook(false)
    .enablePeriodicCheck(false)
    .enableRetrying(true)
    .requestTimeout(60L)
    .build();
} catch (ConfigurationException e) {
  log.error(e.getCause().getMessage());
}
```

## ProxyFloatingService

After setting up the SDK configuration, there are a number of methods and objects available to the app developer.

To make the `ProxyFloatingService`, initialize it by passing the `ProxyConfiguration` object you set up earlier.

```java
ProxyFloatingService service = new ProxyFloatingService(configuration);
```

Now you can use the methods that the `ProxyFloatingService` provides.

### register()

Registers the user by making a `ProxyRequest` which contains the product code from the `ProxyConfiguration` and the device ID which is provided by the `IdentityProvider`. Each registration lasts for the time specified in the LicenseSpring platform (floating timeout). In order to prolong the usage of the product, this method needs to be called periodically (this is automatically called in the background if the property `enablePeriodicRegister` in the `ProxyConfiguration` was set to true). Returns the `LicenseData` object which contains information about the license.

```java
try {
  LicenseData licenseData = service.register();
  System.out.println("You have " + licenseData.getFloatingTimeout() + " more minutes.");
} catch (LicenseSpringException e) {
  log.error(e.getCause().getMessage());
}
```

### unregister()

Unregisters the user, which by definition, frees up one user slot on the server. Returns true if the action was successful.

```java
try {
  if (service.unregister()) {
    System.out.println("You have been successfully unregistered from product " + configuration.getProduct());
  }
} catch (LicenseSpringException e) {
  log.error(e.getCause().getMessage());
}
```

### getLicense()

Fetches the license information from the server for the product specified in the `ProxyConfiguration` object.

```java
try {
  if (service.unregister()) {
    System.out.println("You have been successfully unregistered from product " + configuration.getProduct());
  }
} catch (LicenseSpringException e) {
  log.error(e.getCause().getMessage());
}
```

### getSettings()

Retrievers the server settings. The returned `Settings` object contains `registrationExpiryMinutes`, and an array of server addresses.

```java
try {
  Settings settings = service.getSettings();
  System.out.println("There are " + settings.getServers().length + "in your proxy network.");
  System.out.println("The registration expiry time for product " + configuration.getProduct() + " is " +
                     settings.getRegistrationExpiryMinutes() + " minutes");
} catch (LicenseSpringException e) {
  log.error(e.getCause().getMessage());
}try {
  if (service.unregister()) {
    System.out.println("You have been successfully unregistered from product " + configuration.getProduct());
  }
} catch (LicenseSpringException e) {
  log.error(e.getCause().getMessage());
}
```

### pingServer()

Pings the local proxy server.

```java
try {
  service.pingServer();
  System.out.println("The proxy server is up and running. :)");
} catch (LicenseSpringException e) {
  System.out.println("There is something wrong with your local server, this application cannot connect to it.");
  System.out.println("Please check why: " + e.getCause().getMessage());
}
```


[title] Logging
[path] SDKs/Tutorials/Best Practices/

Logging is a fundamental aspect of software development and system administration, providing a valuable means to record and monitor the activities and events within an application or system.&#x20;

This tutorial aims to equip you with the knowledge and skills to enable logging in your applications or systems effectively.&#x20;

We will explore the essential concepts of logging, such as log levels, log formats, and log destinations.&#x20;

By the end of this tutorial, you will have a clear understanding of how to incorporate logging into your projects and locate log files for analysis and debugging purposes.

## Prerequisites

1. Completed the [**Getting Started**](docId\:LSFY9tQ3vfq4ROOW9sHkd) Tutorial, specifically:
   - Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
   - Created a `LicenseID` using either `LicenseID::fromKey` or `LicenseID::fromUser` function, depending on the activation method you prefer.
   - Implemented basic license management, including license activations, deactivations, and both online and local license checks.

## Enabling Logging and Verifying Its Status

Logging is enabled within the `Configuration` object, prior to the product and license being configured within the application.

:::hint{type="info"}
**Note:&#x20;**&#x4C;ogging is **disabled** by default.
:::

Logging can be enabled using the following method:

:::CodeblockTabs
```cpp
void LicenseSpring::ExtendedOptions::enableLogging( bool enable )	
```

```csharp
bool LicenseSpring.ExtendedOptions.EnableLogging
```

```java
public B requestLogging( feign.Logger.Level requestLogging )
```

```swift
// Just set log handler:
LSLog.log = { level, message in
    print("[\(level)] \(message())")
}
```

```python
import logging

# Configure logging
logging.basicConfig(
    filename='app.log',   # Name of the log file
    filemode='a',         # Append to the file ('w' for overwrite)
    format='%(asctime)s - %(levelname)s - %(message)s',  # Log format
    level=logging.INFO    # Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
)
```
:::

:::hint{type="danger"}
**Warning:&#x20;**&#x4C;ogging is for developer use only, ensure it is disabled in your release builds.
:::

To see how to enable logging in an application environment, see below:

:::CodeblockTabs
```cpp
std::string appName = "NAME"; //input name of application
std::string appVersion = "VERSION"; //input version of application

ExtendedOptions options;
options.enableLogging( true ); 

auto configuration = Configuration::Create(
     EncryptStr( "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" ),
     EncryptStr( "XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX" ), 
     EncryptStr( "XXXXXX" ),
     appName, appVersion, options );

auto licenseManager = LicenseManager::create( pConfiguration );
```

```csharp
var options = new LicenseSpring.ExtendedOptions();
options.EnableLogging = true;

var configuration = new LicenseSpring.Configuration(
            apiKey: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", 
            sharedKey: "XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX", 
            productCode: "XXXXXX", 
            appName: "NAME",
            appVersion: "VERSION",
            extendedOptions: options );
            
var licenseManager = LicenseManager.GetInstance();
licenseManager.Initialize( configuration );
```

```java
LicenseSpringConfiguration configuration = LicenseSpringConfiguration.builder()
                .apiKey( "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" )
                .productCode( "XXXXXX" )
                .sharedKey( "XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX" )
                .appName( "NAME" )
                .appVersion( "VERSION" )
                .requestLogging( Logger.Level.FULL ) 
                .build();

LicenseManager licenseManager = LicenseManager.getInstance();
licenseManager.initialize( configuration );
```

```python
from licensespring.licensefile.config import Configuration
from licensespring.licensefile.license_manager import LicenseID, LicenseManager
import logging

# Configure logging
logging.basicConfig(
    filename='path_where_you_want_to_store_logs/app.log',   # Name of the log file
    filemode='a',         # Append to the file ('w' for overwrite)
    format='%(asctime)s - %(levelname)s - %(message)s',  # Log format
    level=logging.INFO    # Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
)

conf = Configuration(
        product="your_product_short_code",
        api_key="api_key",
        shared_key="shared_key",
        file_key="your_file_key",
        file_iv="file_iv",
        grace_period_conf=12,
        is_guard_file_enabled=True)


lm = LicenseManager(conf)
license_id = LicenseID.from_key("9FFA-2XZC-SNDJ-49LK")
license = lm.activate_license(license_id)
license.check()
```
:::

Developers can chack for whether logging is enabled in the current `Configuration` through using:

:::CodeblockTabs
```cpp
bool LicenseSpring::ExtendedOptions::isLoggingEnabled()
```

```csharp
bool LicenseSpring.Configuration.IsLoggingEnabled
```

```java
feign.Logger.Level getRequestLogging()
```
:::

## Location of the Log File

The location of log files is a critical aspect of logging configuration, determining where logged data is stored and accessed for monitoring, debugging, and analysis purposes.

### Default Location in Different Environments

The location of the log file depends on the operating system in use.

On Windows, the default SDK data location is: `{SystemDrive}:/Users/{UserName}/AppData/Local/LicenseSpring/{ProductCode}`

On Linux, the default SDK data location is: `HOME/.LicenseSpring/LicenseSpring/{ProductCode}`

On macOS, the default SDK data location is: `~/Library/Application Support/LicenseSpring/{ProductCode}`

These default paths indicate where the log file and other SDK-related data are stored based on the specific operating system.

### Getting Current Data Location

Log files are stored in the same location as all other LicenseSpring data, including your local license file.&#x20;

To discover the specific location of this data on your device, you can utilize the corresponding functionality provided within your application.

:::CodeblockTabs
```cpp
std::wstring path = licenseManager->licenseFilePath();
```

```csharp
var path = licenseManager.DataLocation;
```

```java
String path = configuration.getLicenseFilePath();
```

```python
path = lm.data_location()
```
:::

### Changing Data Location

Changing the data location involves modifying the application's configuration or settings to redirect where data, including log files, is stored.&#x20;

Developers and administrators may implement this change to consolidate data in a centralized location, move data to faster storage media, or ensure data privacy and compliance with regulations.

:::CodeblockTabs
```cpp
licenseManager->setDataLocation(L"new/path/to/LicenseSpring/data");
```

```csharp
licenseManager.DataLocation = "new/path/to/LicenseSpring/data";
```

```java
LicenseSpringConfiguration.ClientConfigurationBuilder licenseFilePath( String licenseFilePath )
```

```python
lm.set_data_location("new/path/to/LicenseSpring/data")
```
:::

:::hint{type="danger"}
**Warning:&#x20;**&#x49;f there's a license in the new location, it will be set as current license, otherwise the current license will be removed from memory.
:::


[title] Floating Server Usage
[path] SDKs/Tutorials/Advanced Usage/

Distributing software applications designed for closed networks comes with numerous obstacles.&#x20;

Challenges include implementing node locking on virtual machines and activating licenses meant for devices with strict security demands, often in the absence of internet connectivity.&#x20;

LicenseSpring provides a solution through a [**Floating Server**](docId\:sS5gX73i5CjOrDgK1Ed8I). This server can be set up and customized at your customers' locations, ensuring functionality even when the client application runs on a machine without internet access.

LicenseSpring's offerings encompass both a floating server tailored for private networks and a cloud-based floating license solution. The client SDK functions quite similarly in both situations.&#x20;

To learn more about the processes of registering, deregistering, managing timeouts, and borrowing licenses using a cloud-based floating license, we encourage you to refer to our [**Floating Licensing**](docId\:yaZxsl7FnxbYi883jYc3-).

## Floating Client Identifier

The floating client or instance identifier can be accessed through a `License` object by using:

:::CodeblockTabs
```cpp
string floatingClientID = license->floatingClientId();
```

```csharp
string floatingClientID = license.FloatingClientId();
```

```swift
if let id = license.floatingClientID { ... }
```

```python
client_id = license.floating_client_id()

print(client_id)
```
:::

This floating client identifier is set during registration, within the `register` method shown below.

## Floating Client

The `FloatingClient` class is used to perform requests to LicenseSpring's floating server. Within a `FloatingClient` object, developers are able to:

- Register and unregister clients.
- Borrow licenses.\*
- Retrieve server information.
- Check whether the connection to the floating server is online.

\*Only offered in C++ SDK

### Registering a Client

Developers register clients with the following method:

:::CodeblockTabs
```cpp
License license = floatingClient->registerLicense( id, licenseID );
```

```swift
let floatingClient = FloatingClient(configuration: configuration)
let license = try floatingClient.register(userID: "user id")
```

```python
#floating client
from licensespring.floating_server import FloatingAPIClient

api_client = FloatingAPIClient(api_protocol="http", api_domain="localhost:8080")

response = api_client.register_user(
    product="lkprod1",
    user="user_1",
    os_hostname="bla",
    ip_local="bla",
    user_info="bla",
    license_id=1728377159207169
)

print(response)

#floating manager
from licensespring.licensefile.config import Configuration
from licensespring.licensefile.floating_manager import FloatingManager

conf = Configuration(
    product=product,
    api_key="arbitrary",
    shared_key="arbitrary",
    file_key="your_file_key",
    file_iv="your_file_iv",
    api_domain="api_domain",
    api_protocol="http/https",
)

fs_manager = FloatingManager(conf=conf)
license = fs_manager.register()
```
:::

:::hint{type="info"}
**Note:&#x20;**`id` is the user or instance id used for license registration, it can be anything: email, hostname, handle, etc.&#x20;

`licenseID` is an optional parameter where a specific license identifier can be specified. If no parameter is provided, the license gets the default configuration for the product.
:::

If registration is successful, a shared pointer to the `License` object is returned. If unsuccessful, an exception is thrown.

### Unregistering a Client

The unregister method uses the exact same parameters as register:

:::CodeblockTabs
```cpp
bool unregistered = floatingClient->unregisterLicense( id, licenseID );
```

```csharp
bool unregistered = floatingClient.Unregister( id, licenseID );
```

```swift
try floatingClient.unregister(userID: "user id")
```

```python
#floating client
from licensespring.floating_server import FloatingAPIClient

response = api_client.unregister_user(product="lkprod1",user="user_1",license_id=1728377159207169)

print(response)

#floating manager
from licensespring.licensefile.config import Configuration
from licensespring.licensefile.floating_manager import FloatingManager

conf = Configuration(
    product=product,
    api_key="arbitrary",
    shared_key="arbitrary",
    file_key="your_file_key",
    file_iv="your_file_iv",
    api_domain="api_domain",
    api_protocol="http/https",
)

fs_manager = FloatingManager(conf=conf)
# There are multiple options to unregister a license
# 1. floating client -> this one is documanted
fs_manager.unregister()
# 2.1. license object -> deactivate method
license.deactivate() 
#2.2 license object -> floating release
license.floating_release(False)
```
:::

This Boolean result is set to true if the client was unregistered successfully.

### License Borrowing

Only available in the C++ SDK, the following method allows developers to register and borrow licenses at once:

:::CodeblockTabs
```cpp
License license = floatingClient->borrowLicense( id, borrowEndDateTime );
```

```swift
try license.borrow(for: 24 * 60 * 60) // 1 day.
```

```python
# floating client
from licensespring.floating_server import FloatingAPIClient

api_client = FloatingAPIClient(api_protocol="http", api_domain="localhost:8080")

response = api_client.borrow(
        product="lkprod1",
        user="user_1",
        borrowed_until="2029-05-06T00:00:00Z",
        os_hostname="bla",
        ip_local="bla",
        user_info="bla",
        license_id=1728377159207169,
    )

# floating manager
from licensespring.licensefile.config import Configuration
from licensespring.licensefile.floating_manager import FloatingManager

conf = Configuration(
    product=product,
    api_key="arbitrary",
    shared_key="arbitrary",
    file_key="your_file_key",
    file_iv="your_file_iv",
    api_domain="api_domain",
    api_protocol="http/https",
)

fs_manager = FloatingManager(conf=conf)
license = fs_manager.borrow("2031-05-06T00:00:00Z")
# borrow can be also used within the License object
license.floating_borrow("2031-05-06T00:00:00Z")
```
:::

:::hint{type="info"}
**Note:&#x20;**&#x54;he `id` parameter is the user or instance identifier used for license registration. `borrowEndDateTime` is the borrow end date time in format **"%Y-%m-%dT%H:%M:%SZ"**, for example "2022-05-28T15:30:00Z".
:::

:::hint{type="danger"}
`borrowLicense()` can throw the same exceptions as on registration and License::borrow, see those methods for more details.
:::

For more information about license borrowing, see our [**Floating Licensing**](docId\:yaZxsl7FnxbYi883jYc3-).

### Floating Server and License Information

A helper method for checking the connection the floating server is provided within the `FloatingClient` object:

:::CodeblockTabs
```cpp
bool online = floatingClient->isOnline();
```

```csharp
bool online = floatingClient.IsOnline();
```

```swift
let online: Bool = floatingClient.checkConnection()
```

```python
from licensespring.licensefile.config import Configuration
from licensespring.licensefile.floating_manager import FloatingManager

conf = Configuration(
    product=product,
    api_key="arbitrary",
    shared_key="arbitrary",
    file_key="your_file_key",
    file_iv="your_file_iv",
    api_domain="api_domain",
    api_protocol="http/https",
)

fs_manager = FloatingManager(conf=conf)
response = fs_manager.is_online()
```
:::

:::hint{type="info"}
**Note:&#x20;**`isOnline()` methods have an optional parameter, `throwExceptions`, that indicates whether the method should throw exceptions.
:::

Using the `FloatingClient` object, developers are also able to access a `FloatingServerInfo` object with:

:::CodeblockTabs
```cpp
FloatingServerInfo floatingServerInfo = floatingClient->getServerInfo();
```

```csharp
FloatingServerInfo floatingServerInfo = floatingClient.GetServerInfo();
```
:::

`FloatingServerInfo` consists of:

- `RegistrationExpiry` - The floating server registration expiry in minutes.
- `Servers` - The list of floating server IP addresses available in the network.

In the .NET SDK, it is also possible to get the license information for a configured product with:

```csharp
License license = floatingClient.GetLicenseInfo();
```

:::hint{type="info"}
**Note:&#x20;**&#x54;here is an optional parameter for `GetLicenseInfo()`, where a specific license identifier can be specified. If no parameter is provided, the license gets the default configuration for the product.
:::

See our [**Get license**](docId\:ES5anHxOa67aUTSvIE2p5) documentation for more information.

[title] List Devices
[path] Management API/Device/

Show all devices the requesting manager has access permissions to.

**URL**: `/api/v1/devices/`

**Method**: `GET`

### Query Parameters:

### Ordering:

- `order_by` - Which attribute to order the list by.
  - default ordering is ascending, can be made descending by prefixing the attribute name with `-`
  - Example: `order_by=created_at`
  - Example: `order_by=-created_at`

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on device or related to the device.

Possible filters:

- `license`
- `blacklisted`
- `hostname`
- `hardware_id`
- `os`
- `license_users__id`
- `device_active`
- `type`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "count": 10,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 1590981949868340,
            "device_variables": [],
            "created_at": "2020-06-02T10:32:54Z",
            "updated_at": "2020-06-02T12:35:17Z",
            "hardware_id": "1C0B-D53D-2A92-9665-9634-1FE5-1326-56DF-5401-63B1-88D5-DB7D-FB02-D440-3760-720D",
            "time_activated": "2020-03-11T10:22:29Z",
            "time_deactivated": null,
            "validity_period": null,
            "device_active": true,
            "type": "desktop",
            "os": "Microsoft Home 10",
            "sdk_build_version": "Java SDK 0.0.1",
            "last_check": "2020-03-13T11:04:45Z",
            "app_ver": "1.0.",
            "hostname": "DESKTOP-2K64QES",
            "ip": "192.168.202.1",
            "external_ip": "46.234.71.160",
            "mac_address": null,
            "is_vm": true,
            "vm_info": "VMware ESX 3",
            "floating_last_seen": null,
            "floating_in_use": false,
            "blacklisted": false,
            "license": {
                "id": 1606461720853199,
                "license_key": null
            }
        },
        ...
    ]
}
```


[title] Floating Server V2
[path] SDKs/Tutorials/Advanced Usage/Floating Server Usage/

LicenseSpring SDKs support both Floating Server v1 and v2. Here we demonstrate how to retrieve and register licenses on Floating Server v2.

In some SDKs you can reuse the same interface for handling licenses on Floating Server v1, with an additional function used for fetching all floating licenses tied to a single product. Each license has its own 64-bit integer `license_id`, called the server-side license ID in LicenseSpring SDKs.

## Certificate and signature verification

Each Floating Server instance has its own private key used for signing response payloads, and you should have received a certificate chain tied to your instance.

To verify the certificate and to verify signatures returned by the Floating Server, you must enter the whole certificate chain into the SDK. You can do it by specifying an absolute or relative path to the chain PEM file, or input the whole chain as a string constant:

:::CodeblockTabs
c++

```cpp
#include <LicenseSpring/ExtendedOptions.h>

options.setCertificateChainFromFile("chain.pem");
// or
options.setCertificateChain(R"(...cert...)");
```

```csharp
options.setCertificateChainFromFile("chain.pem");
// or
options.CertificateChain = "(...cert...)";
```

```python
# API client configuration
from licensespring.floating_server import FloatingAPIClient

api_client = FloatingAPIClient(api_protocol="http",api_domail="localhost:8080",certificate_chain_path="path_to_pem_file/chain.pem")

# Floating Manager configuration
from licensespring.licensefile.config import Configuration
from licensespring.licensefile.floating_manager import FloatingManager

conf = Configuration(product="your_product_key",api_key="your_api_key",
                   shared_key="your_shared_key",file_key=key,file_iv=iv,
                   is_guard_file_enabled=True,certificate_chain_path="path_to_pem_file/chain.pem")

fs_manager = FloatingManager(conf=conf)
```
:::

:::hint{type="warning"}
If you're getting a `License signature is not valid` error or a similar verification error, you're missing the Floating Server certificate chain, or set the wrong one.
:::



## Authentication and license registration

Registering and using a license requires users to be logged in to an account created on the Floating Server. The SDK manages token lifetime automatically.

:::CodeblockTabs
```cpp
#include <LicenseSpring/FloatingClient.h>
#include <LicenseSpring/ExtendedOptions.h>

// ...

LicenseSpring::ExtendedOptions options;
options.setCertificateChainFromFile("chain.pem");
// or
options.setCertificateChain(R"(...cert...)");
// and other options ...

auto config = LicenseSpring::Configuration::Create(/*...*/);
auto fc = LicenseSpring::FloatingClient::create(config);

// Authenticate the user if it is required
// You should first create the user on the Floating server itself
fc->authenticateUser("user", "pass");

// FloatingClient::getAllLicenses returns one LicenseID for each license tied to the configured product code
std::vector<LicenseSpring::LicenseID> licenseIds = fc->getAllLicenses();

// check if at least one license exists
if (licenseIds.empty())
    return 1;
    
for (const auto &licenseId : licenseIds)
{
    std::cout << "Server-side license ID: " << licenseId.serverId();
    // licenseId.key() will return the license key of the license
}
    
// register the first license, same as on Floating Server v1
auto licenseId = licenseId.front();
std::string username = "John";
auto license = fc->registerLicense(username, licenseId); 
```

```csharp
var floatingClient = new FloatingClient();
floatingClient.Initialize( lsConfig );

var licenseIds = floatingClient.getAllLicenses();

// check if at least one license exists
if (!licenseIds.Any())
    return;

foreach (LicenseID licenseId in licenseIds)
{
    Console.WriteLine("Server-side license ID: " + licenseId.ServerId);
    // licenseId.Key and licenseId.User will return empty strings
}

// register the first license, same as on Floating Server v1
var username = "John"; 
var licenseId = licenseIds[0];
license = floatingClient.Register(username, licenseId);
```
:::

:::hint{type="danger"}
Manually setting up a license ID with the license key, or a username and password combination does not work in Floating Server V2.
:::


[title] List Activities
[path] Management API/Analytics/

Show all activities the requesting manager has access permissions to.

**URL**: `/api/v1/activities/`

**Method**: `GET`

### Query Parameters:

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on customer account or related to the customer account.

Possible filters:

- `action__in`
  - values can be `consumption`, `f_consumption`, `check`, `activation`, `deactivation`, `activation_offline`, `deactivation_offline`, `trial_key`, `keygen`, `order`, `license_issued`, `change_password`, `customer_license_users`, `floating_release`, `installation_file`, `versions`, `product_details`, `get_device_variables`, `track_device_variables`, `ping`, `single_sign_on`, `floating_borrow`
- `product__in`
- `license__in`
- `status_code__in`
- `ts__*`
  - `*` can be `lte`, `gte`, `lt`, `gt`
- `status_code__*`
  - `*` can be `lte`, `gte`, `lt`, `gt`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "count": 604,
    "next": "http://127.0.0.1:5000/api/v1/activities/?limit=20&offset=20",
    "previous": null,
    "results": [
        {
            "id": 11475,
            "ts": "2020-07-07T12:35:29Z",
            "action": "order",
            "count": 1,
            "extra": null,
            "status_code": 200,
            "company": 277,
            "product": null,
            "license": null
        },
        ...
    ]
}
```


[title] List Hourly Activities Top Call Counts For Orders
[path] Management API/Analytics/Hourly Activities/

Show all hourly activities top call counts for orders the requesting manager has access permissions to.

**URL**: `/api/v1/activities-hourly/top_call_count_orders/`

**Method**: `GET`

### Query Parameters:

### Pagination:

Default pagination is 20 results per page.

- `limit` - Number of results to return per page.
  - Example: `limit=20`
- `offset` - The initial index from which to return the results.
  - Example: `offset=21`

### Filtering:

The results can be filtered by various attributes on customer account or related to the customer account.

Possible filters:

- `action__in`
  - values can be `consumption`, `f_consumption`, `check`, `activation`, `deactivation`, `activation_offline`, `deactivation_offline`, `trial_key`, `keygen`, `order`, `license_issued`, `change_password`, `customer_license_users`, `floating_release`, `installation_file`, `versions`, `product_details`, `get_device_variables`, `track_device_variables`, `ping`, `single_sign_on`, `floating_borrow`
- `product__in`
- `license__in`
- `status_code__in`
- `ts__*`
  - `*` can be `lte`, `gte`, `lt`, `gt`, `date__lte`, `date__gte`, `date__lt`, `date__gt`
- `status_code__*`
  - `*` can be `lte`, `gte`, `lt`, `gt`

### Success Response:

**Code**: `200 OK`

**Content Examples**:

```json
{
    "count": 118,
    "next": "http://127.0.0.1:5000/api/v1/activities-hourly/top_call_count_orders/?limit=20&offset=20",
    "previous": null,
    "results": [
        {
            "id": 1620743980430739,
            "created_at": "2021-05-11T14:39:40Z",
            "store_id": "e00edd2c113143959a49df8488259557",
            "customer": {
                "id": 1136,
                "email": "zaher.leon@gmail.com",
                "first_name": "Leon",
                "last_name": "Zaher",
                "company_name": ""
            },
            "total_call_count": 12663
        },
```


[title] Removing a License
[path] Floating Server/Floating Server V1/Best Practices/

Removing a product license from your Floating Server can be done easily through our API or on the Floating Server UI itself. This process is especially useful when managing licenses dynamically or when decommissioning products.

## Using the User Interface

For those preferring a graphical approach to manage licenses, the Floating Server's UI provides a straightforward method to remove product licenses.

1. **Navigate to the Products Page**:
   Access the Floating Server UI and navigate to the `Products` tab from the top menu.
2. **Locate the Product**:
   In the products list, locate the product you wish to remove. You can use the search function if you have many products listed.
3. **Remove the Product**:
   Click the `Remove` button located in the `Remove product` column corresponding to the product you want to delete.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/RJdV0U90j56mQbCtwFdGF_image.png)

### API Endpoint

**Endpoint**: `GET http://localhost:8080/api/v4/removeProduct` This API call is used to remove a license for a product from the Floating Server.

### Required Parameters

- **product (string)**: The identifier for the product whose license you want to remove.

## Using the API

To remove a product license, you will need to make a GET request to the endpoint with the appropriate query parameters. For more information on how to remove a product license with the Floating Server API, see [**Remove license**](docId:3S2kISByrV5R4Dvc8l-dr).




[title] v2
[path] SDKs/Go SDK/


[title] License Handler
[path] SDKs/Go SDK/v2/

# License Handler

The LicenseHandler is the primary entry point to the SDK. It orchestrates the license activation and storage by combining two modules:

- [**LicenseManager**](): Handles license logic, requests, and validations.
- [**Storage**](): Persists license data (e.g., license files, guard files) securely.

We provide a single setup function, SetupHandler, which simplifies configuration and lets you use either API Key authentication or OAuth.

The `NewLicenseHandler` function is the primary way to set up and use the SDK. It initializes and connects the core modules.

Overview

:::CodeblockTabs
go

```go
func NewLicenseHandler(
    config LicenseHandlerConfig,
) (*LicenseHandler, error)
```
:::

**config**: Required configuration fields such as API keys, product code, and license key.

## What It Returns

Calling `NewLicenseHandler` constructs and returns a fully functional `*LicenseHandler `with:

- A configured LicenseManager
- A configured Storage backend
- A unified interface to handle license activation, checking, and storage operations

## Basic Setup

### Minimal Setup with Defaults

```go
lm_config := license_manager.LicenseManagerBasicConfiguration{
				OAuth:             false,
				ApiKey:            "your-api-key",
				SharedKey:         "your-shared-key",
				ProductCode:       "your-product-code",
				AuthData:          auth.FromKey("LICENSE-KEY"),
			}
cfg := license_handler.LicenseHandlerConfig{
    lm_config,
}

lh, err := license_handler.NewLicenseHandler(cfg)
if err != nil {
    log.Fatal(err)
}
```

This will use:

- API key authentication
- Default license manager
- Default file-based storage with encryption using the shared key

## Advanced Usage

### Providing a Custom LicenseManager

```go
lm_config := license_manager.LicenseManagerBasicConfiguration{
				OAuth:             false,
				ApiKey:            "your-api-key",
				SharedKey:         "your-shared-key",
				ProductCode:       "your-product-code",
				AuthData:          auth.FromKey("LICENSE-KEY"),
			}

lm, _ := license_manager.NewLicenseManager(
    lm_config,
    license_manager.WithRestyVerbose(true),
    license_manager.WithHardwareId("ABC"),
)

cfg.Manager = lm

lh, _ := license_handler.NewLicenseHandler(cfg)

```

## OAuth Setup

When using OAuth, you have two options:

**Manually create a LicenseManager using OAuth** and inject it into the handler config

```go
lm_config := license_manager.LicenseManagerBasicConfiguration{
				OAuth:             true,
				ClientId:          "your-client-id",
				ClientSecret:      "your-client-secret",
				ProductCode:       "your-product-code",
				AuthData:          auth.FromKey("LICENSE-KEY"),
			}
			
lm, _ := license_manager.NewLicenseManager(
    lm_config,
)

cfg.Manager = lm

lh, _ := license_handler.NewLicenseHandler(cfg)
```

**Provide OAuth-related fields via configuration object**, allowing NewLicenseHandler to construct the manager internally

```go
cfg := license_handler.LicenseHandlerConfig{
    OAuth: true,
    ProductCode: "your-product-code",
    AuthData:    auth.FromKey("LICENSE-KEY"),
    ClientId:      "placeholder",
    ClientSecret:   "placeholder",
    CryptoProviderKey: "placeholder",
}

lh, err := license_handler.NewLicenseHandler(cfg)
if err != nil {
    log.Fatal(err)
}
```

## License Manager Configuration Options

To initialize the SDK, you must provide basic credentials, such as the API key and shared key (or client ID and client secret in OAuth mode), along with the product code and license authentication credentials. These are required when calling `NewLicenseManager()` and must be passed using the `LicenseManagerBasicConfiguration` struct.

Additional configuration options, such as the hardware ID algorithm, grace period, and other settings, come with sensible defaults. However, you can override them using optional configuration functions, which are explained in the following sections.

```go
type LicenseManagerBasicConfiguration struct {
	OAuth        bool
	ClientId     string
	ClientSecret string
	ApiKey       string
	SharedKey    string
	ProductCode  string

	AuthData auth.Auth
}
```

The LicenseManager can be customized using a variety of configuration options. These options allow you to control how the SDK behaves under different conditions such as air-gapped environments, logging preferences, offline handling, and more.

### Available Options

```go
WithRestyLogger(restyLogger resty.Logger)
WithAirGapPublicKey(airgappublickey string)
WithGracePeriod(gracePeriod int)
WithSyncPeriod(syncPeriod int)
WithRestyVerbose(verbose bool)
WithVerifySignature(verifySig bool)
WithEnableGuardFile(enableGuardFile bool)
WithHardwareId(hardwareId string)
WithBaseURL(url string)
WithHardwareIdAlgo(algo int)
WithMachineId()
WithServerPublicKey(publickey string)
WithAppName(appName string)
WithAppVersion(appVersion string)
```

Each of these options can be passed to `NewLicenseManager(...)` or `NewLicenseManagerOAuth(...)` as variadic arguments to modify the default behavior.

### Special Note on Air-Gapped Licenses

When working with air-gapped licenses, you **must** set the AirGapPublicKey. This can be done either during initialization or afterward:

```go
lh, _ := license_handler.NewLicenseHandler(cfg)
lh.LicenseManager.LicenseClient.LicenseClientConfiguration.AirGapPublicKey = "x"
```

More detailes about the configuration options can be found in [**Configuration Options.**](https://app.archbee.com/docs/FbT_Z5Cu33D-LVZx1fRkU/2-GE9mJAYb2MrSTfs5xpG)

## Providing Custom Storage with a Custom Crypto Provider

```go
cp := crypto_provider.DefaultCryptoProvider{}
cp.SetKey(cfg.SharedKey)

fs := data_handler.DefaultFileStorage{}
fs.SetCryptoProvider(&cp)

cfg.Storage = fs

lh, err := license_handler.NewLicenseHandler(cfg)
lh.LicenseManager.LicenseClient.AirGapPublicKey = "your airgap public key"

```

## LicenseHandlerConfig Fields

```go
type LicenseHandlerConfig struct {
	OAuth             bool
	ClientId          string
	ClientSecret      string
	CryptoProviderKey string
	ApiKey            string
	SharedKey         string
	ProductCode       string
	AuthData          auth.Auth
	Verbose           logger.VerboseLevel

	Manager *license_manager.LicenseManager // optional

	Storage data_handler.FileStorage // optional
}

```

- ApiKey, SharedKey, ProductCode, and AuthData are required if you are using a api authention method. if using OAuth, set OAuth to true, and in that case, clientId, clientId and cryptoProviderKey are required.
- Manager and Storage are optional and allow injecting custom components.




[title] Air-Gap License
[path] SDKs/Go SDK/v2/Samples/

# Air-Gap License Activation

In highly secure environments where systems are completely disconnected from the internet (air-gapped), standard online or offline activation methods involving file exchange may not be suitable. To address this, the LicenseSpring SDK offers an **Air-Gap Activation** mechanism using code-based exchange.

This guide explains how to use the air-gap flow to activate licenses without transferring files.

## Overview of the Air-Gap Flow

1. **Retrieve an Initialization Code** from the LicenseSpring Air-Gap Portal.
2. **Generate an Activation Code** using the SDK and the initialization code.
3. **Submit the Activation Code** to the Air-Gap Portal and obtain a **Confirmation Code**.
4. **Activate the License** on the air-gapped machine using the confirmation code and policy data.

Each step is handled by SDK functions that require certain inputs provided via the portal or platform settings.

## Step 1: Generate Activation Code

Use the initialization code retrieved from the air-gap portal to generate an activation code:

```go
	// Generate an activation code using the initialization code and license key.
	// This code must be submitted to the Air-Gap Portal to receive a confirmation code.
	activationCode, err := lh.GetAirGapActivationCode(initializationCode, licenseKey)
	if err != nil {
		fmt.Printf("failed to generate air-gap activation code: %w", err)
		return err
	}
	fmt.Printf("Activation Code: %s\n", activationCode)
```

- `initializationCode`: Provided by the Air-Gap Portal.
- `licenseKey`: Retrieved from the authentication data provided in configuration.

Print and store the activation code. You will paste this back into the Air-Gap Portal to obtain a confirmation code.

## Step 2: Activate License Using Confirmation Code

After receiving the confirmation code and downloading the associated policy file, use the following function to activate the license:



```go
	// Complete the activation using the confirmation code and policy file.
	ld, err = lh.ActivateAirGapLicense(confirmationCode, policyPath, licenseKey, policyId)
	if err != nil {
		fmt.Println("error during air-gap activation:", err)
		return err
	}
```

### Required Inputs:

- `confirmationCode`: Obtained from the Air-Gap Portal.
- `policyPath`: Local path to the policy file (must be included with your application).
- `licenseKey`: Retrieved from License Handler's configuration.
- `policyId`: Found on the LicenseSpring portal and the Air-Gap protal.
- `airgapPublicKey`: The air-gap public key from portal settings.

## Notes

- Air-Gap activation does not require file export/import, only copying codes between the portal and the SDK.
- Ensure the policy file is shipped with your software as it is required for activation.
- Both activation and configuration require the correct Air-Gap Public Key, available in your LicenseSpring settings.


[title] Which to Use?
[path] Floating Server/Floating Server V1/License Options/

Selecting the correct license type is crucial for maximizing the functionality and security of your software. This section provides guidance on choosing the appropriate license type based on your operational environment and needs.

### [**Online**](docId\:Mp97oEzkfYsO1k9CnRBcO) Licenses:

- **Ideal For**: Environments with reliable internet connectivity.
- **Advantages**: Allows real-time validation and management of licenses, suitable for dynamic or cloud-based settings.
- **Use Case**: Best for organizations that can handle online checks and need flexibility in managing and reallocating licenses on-the-fly.

### [**Offline**](docId\:Eart7MueBAMUV6qpdsXR5) Licenses:

- **Ideal For**: Settings with limited or unreliable internet access.
- **Advantages**: Works without the need for continuous internet connectivity, ensuring functionality in remote or mobile scenarios.
- **Use Case**: Suitable for applications used in remote locations where internet access is intermittent or unavailable.

### [**Air-Gapped**](docId\:LkwCIEpf4IL90uID7wymk) Licenses:

- **Ideal For**: High-security environments that must operate completely isolated from the internet.
- **Advantages**: Provides the highest level of security by operating without any external network connections.
- **Use Case**: Optimal for highly sensitive or secure installations such as governmental or military applications where no external communication is permitted.

### [**Hardware Key**](docId:5VSC4S8pfXIbwHppAC0LI)  Licenses:

- **Ideal For**: Environments where physical security and anti-piracy measures are paramount.
- **Advantages**: Offers a physical element to the licensing process, which can be more secure against certain types of tampering.
- **Use Case**: Effective for small-scale deployments where software needs to be tightly controlled and bound to specific hardware.

### **Deciding Factors to Consider**

- **Security Requirements**: Choose **Air-Gapped** or **Hardware Key** licenses for maximum security. **Online** licenses offer secure real-time validation.
- **Connectivity**: Opt for **Online** licenses if connectivity is consistent; choose **Offline** or **Air-Gapped** licenses for environments with limited or no internet access.
- **Flexibility and Management**: **Online** licenses provide the most flexibility in management and reallocation, whereas **Hardware Key** licenses add a layer of physical security.
- **Regulatory Compliance**: Ensure your licensing strategy complies with any industry regulations, which might favor one type over another based on data security standards.


[title] Hardware Key Support
[path] Floating Server/Floating Server V1/Deployment Methods/Kubernetes (Helm)/

As of v1.5.0 the Floating Server supports using hardware keys (Yubikey) as a license protection method. If a license requires the usage of a hardware key a valid provisioned key must be accessible from the Pod running the floating server.&#x20;

## Limitations

1. Only one replica running at the same time - no HA support as of now
2. The pod running the floating server is tied to the node which has the key connected

## Requirements

1. Kubernetes node in which a yubikey can be inserted.
   If running in a VM, the hypervisor must have USB passthrough support and configured.
2. A way to passthrough the hardware key to the pod running the floating server.&#x20;
   Akri [**https://docs.akri.sh/**](https://docs.akri.sh/)
   Generic Device Plugin [**https://github.com/squat/generic-device-plugin**](https://github.com/squat/generic-device-plugin)

## General

**Getting the udev information for the device.&#x20;**

1. First get the device bus and device ID with `lsusb`
2. &#x20;Combine them into` /dev/bus/usb/<bus_id>/<device_id>`
3. Using `udevadm` get the atribbutes for the device&#x20;
   `udevadm info --attribute-walk --path=$(udevadm info --query=path /dev/bus/usb/<bus_id>/<device_id>)`

Usually for Yubikeys these attributes are enough. But results may vary depending on system.&#x20;
`SUBSYSTEM=="usb", ATTR{idProduct}=="0407", ATTR{idVendor}=="1050"`

**Setting up the floating server helm chart for use with a hardware key**

1. Set `.Values.hardwareKeySupport = true `- disables replicas, values for `.Values.replica` will be ignored and set to 1

## Example - Akri plugin

1. Install and configure Akri with udev discovery&#x20;
   [**https://docs.akri.sh/user-guide/getting-started**](https://docs.akri.sh/user-guide/getting-started)
2. Add a udev rule for Yubikey as a separate configuration or as part of the helm chart values. (Examples 1-2 below)
3. Add the akri flags to `.Values.resoruces.limits` and `.Values.resources.requirments`

**Example 1** - akri configmap

:::CodeblockTabs
YAML

```yaml
apiVersion: akri.sh/v0
kind: Configuration
metadata:
  name: akri-yubikey # Name we later use to get the resource
spec:
  capacity: 1
  discoveryHandler:
    discoveryDetails: |
      groupRecursive: true # Recommended unless using very exact udev rules
      udevRules:
      # udev attributes we gathered from udevadm
       - SUBSYSTEM=="usb", ATTR{idProduct}=="0407", ATTR{idVendor}=="1050"
    name: udev
```
:::

**Example 2** - setting udev rules via helm values - akri chart

```yaml
udev:
  configuration:
    # enabled defines whether to load a udev configuration
    enabled: true
    # name is the Kubernetes resource name that will be created for this
    # udev configuration
    name: akri-yubikey
    # brokerProperties is a map of properties that will be passed to any instances
    # created as a result of applying this udev configuration
    discoveryDetails:
      # groupRecursive defines whether to group discovered parent/children under the same instance
      groupRecursive: true
      # udevRules is the list of udev rules used to find instances created as a result of
      # applying this udev configuration
      udevRules:
        - SUBSYSTEM=="usb", ATTR{idProduct}=="0407", ATTR{idVendor}=="1050"
```

**Example 3** - resource values for floating server chart

```yaml
hardwareKeySupport: true

resources:
  requests:
    cpu: 50m
    memory: 64Mi
    akri.sh/akri-yubikey: "1"
  limits:
   # cpu: 200m
   # memory: 256Mi
    akri.sh/akri-yubikey: "1"
```
















[title] Online Licenses
[path] SDKs/Go SDK/v2/Samples/

# Online Licenses

The SDK provides support for online license activation, check, and deactivation. This flow requires internet access and communicates directly with the LicenseSpring API.

## 1. Initialize the License Handler

To begin working with an online license, you must initialize a `LicenseHandler` using your product and license credentials:

### Without OAuth

```go
	c := license_handler.LicenseHandlerConfig{
		ApiKey:      "your api key",
		SharedKey:   "your shared key",
		ProductCode: "your product code",
		AuthData:    auth.FromKey("your license key"),
		OAuth:       false,
	}

	lh, err := license_handler.NewLicenseHandler(c)
```

### With OAuth

When using OAuth, you must provide a `CryptoProviderKey`, which is required to securely encrypt and decrypt the license data.

```go
	c := license_handler.LicenseHandlerConfig{
		ClientId:      "your client ID",
		ClientSecret:   "your client secret",
		CryptoProviderKey: "your crypto key",
		ProductCode: "your product code",
		AuthData:    auth.FromKey("your license key"),
		OAuth:       false,
	}

	lh, err := license_handler.NewLicenseHandler(c)
```

By default, this setup uses the SDK’s **file-based storage**, meaning license data is persisted to a local file. You can customize the storage method if needed, but all examples in this guide assume file storage.

## 2. Activate the License

Once the license handler is configured, activate the license:

```go
	ctx := context.Background()
	var ld *types.LicenseData
	ld, err = lh.ActivateLicense(ctx)
	if err != nil {
		return err
	}
```

This will send an activation request to the LicenseSpring API. If successful, the SDK stores the license locally for future use.

## 3. Check the License

After activation, you can verify the license status at any time:

```go
	ld, err = lh.CheckLicense(ctx)
	if err != nil {
		return err
	}
```

This communicates with the API to ensure the license is still valid and up-to-date.

## 4. Deactivate the License

To deactivate the license when no longer needed:

```go
	removeLocalData := true
	ld, err = lh.DeactivateLicense(ctx, removeLocalData)
	if err != nil {
		return err
	}
```

Setting removeLocalData to true will delete the local license file. If set to false, the file remains and can be reused later.

## 5. Resume from Local License File

If your application restarts and you haven't removed the local license file, you can resume the license state from disk:

```go
	ld, err = lh.GetCurrentLicense()
	if err != nil {
		return err
	}
```

## Notes

- Online licenses require internet connectivity at the time of activation and checks.
- Local license data can be reused as long as it hasn’t been removed or expired.


[title] Unity SDK
[path] SDKs/

# LicenseSpring Unity SDK beta - Beginner's Guide

Welcome to the LicenseSpring Unity beta SDK! This guide will help you understand and use the Unity SDK sample application.

## 1. Introduction

### Where to download?

[**LicenseSpring .Net SDK**](https://docs.licensespring.com/sdks/dot-net)

### What is the LicenseSpring Unity SDK?

The LicenseSpring Unity SDK is a software licensing solution that integrates with Unity projects. It enables you to:

- Activate and validate software licenses
- Manage floating licenses for concurrent usage
- Track license consumption and usage
- Implement offline (air-gapped) activation
- Store license data securely on the local device
- Generate hardware-based device fingerprints

This SDK was tested on .NET Standard 2.1 framework, ensuring compatibility with Unity's scripting backend and IL2CPP (Intermediate Language to C++) compilation.

### What Does This Sample Demonstrate?

The UnitySample project is a fully functional demonstration that shows:

- How to initialize the SDK
- License activation with a license key
- License validation and checking
- License deactivation
- Floating license borrowing and release
- Consumption tracking for usage-based licenses
- Device variable management
- Working with local license file storage

This sample provides a complete UI that lets you test all these features interactively, and is easily expandable should you wish to test additional features yourself.

## 2. Prerequisites

Before you begin, ensure you have:

1. **Unity Hub installed** (download from [**https://unity.com/download**](https://unity.com/download))
2. **Unity version 6000.2.9f1** (or a compatible version)
   - This is the Unity LTS (Long Term Support) version
   - You can install it through Unity Hub
   - This demo was created using this Unity version
3. **LicenseSpring Account Credentials:**
   - API Key
   - Shared Key
   - Product Code (create a product on the LicenseSpring platform)
4. These are provided by your LicenseSpring account administrator. You'll need to provide these in the Config.cs file (see Section 6).
5. **Basic Unity knowledge is helpful but not required**
   - This guide will walk you through the process of setting up the Unity sample step-by-step

## 3. Opening the Project

### Instructions

1. Launch Unity Hub
2. Click the "Add" button → Add project from disk
3. Navigate to the UnitySample folder:

```text
Location: Your-download-location\LicenseSpring\UnitySample
```

1. Click "Open" to add the project to Unity Hub
2. Click on the project in Unity Hub to launch it with Unity Editor

### First-Time Project Load

The first time you open the project, Unity will import all assets. This may take a few minutes. You'll see a progress bar as Unity processes:

- Scripts
- DLL files
- Scenes
- Settings

### Automatic Scene Loading

The sample project includes a helpful editor script (`DefaultSceneLoader.cs`) that automatically opens the main scene (`SampleScene.unity`) when you first load the project. You don't need to manually locate and open the scene!

If you ever need to manually open the scene:

1. In the Unity Editor, locate the Project window (bottom/right panel, next to the Console window)
2. Navigate to: Assets > Scenes
3. Double-click "SampleScene.unity"

## 4. Project Structure

The UnitySample project is organized as follows:

```text
UnitySample/
├── Assets/
│   ├── Plugins/
│   │   └── LicenseSpring/         ← SDK DLLs LOCATED HERE (IMPORTANT!)
│   ├── Scripts/                   ← Application scripts
│   ├── Scenes/                    ← Unity scenes
│   │   └── SampleScene.unity      ← Main scene
│   ├── Settings/                  ← Unity render pipeline settings
│   └── LicenseSpringLogo.png      ← LicenseSpring logo asset
├── ProjectSettings/               ← Unity project configuration
├── Packages/                      ← Unity package manifest
└── Build/                         ← Build output directory
```

### SDK DLL Location

:::hint{type="warning"}
LicenseSpring SDK DLL and dependencies are located in
`Assets/Plugins/LicenseSpring/`
:::

This folder contains:

- **LicenseSpring.dll**
  - The main SDK library with all licensing functionality
- **LicenseSpring.xml**
  - API documentation for IntelliSense in Visual Studio
- **hardware\_id\_generator.dll**
  - Native library for generating hardware-based device fingerprints

:::hint{type="warning"}
The HWID generator file is OS dependent, the sample uses windows x64 version, if you're running on another OS you need to replace this file with a corresponding version distributed with the SDK
:::

- Other assorted required dlls

### Scripts Organization

The `Assets/Scripts/` folder contains the application logic:

- `Config.cs` - SDK configuration and credentials
- `LicenseSpringManager.cs` - SDK lifecycle and license operations
- `LicenseManagementUI.cs` - Activation/deactivation UI controller
- `LicenseDetailsUI.cs` - License information display
- `ProductDetailsUI.cs` - Product information display
- `Editor/DefaultSceneLoader.cs` - Auto-loads scene on project open

## 5. Script Architecture

Understanding how the scripts work together:

### Config.cs - Configuration and Credentials

This static class holds your LicenseSpring credentials and configuration:

- **ApiKey:** Your LicenseSpring API key
- **SharedKey:** Your shared secret key for encryption
- **ProductCode:** Your product identifier

The `CreateConfiguration()` method:

- Builds a Configuration object with your credentials
- Sets up ExtendedOptions (logging, network info, file paths, etc.)
- Returns a ready-to-use configuration

You'll modify this file to add your own credentials.

### LicenseSpringManager.cs - SDK Lifecycle Manager

This is the core singleton manager that handles all SDK operations:

**Key Responsibilities:**

- Initializes the SDK on application startup
- Provides a global access point via Instance property
- Manages license activation and deactivation
- Handles local license file operations

**Important Methods:**

- `InitializeSdk()` - Initializes SDK (called automatically)
- `ActivateLicense(key)` - Activates a license with provided key
- `DeactivateCurrentLicense()` - Deactivates the active license
- `ClearLocalStorage()` - Deletes local license files
- `GetDataLocation()` - Returns license file storage path
- `IsInitialized` - Property to check if SDK is ready

**Singleton Pattern:**

Only one instance exists throughout the application lifecycle. Access it via: `LicenseSpringManager.Instance`

:::hint{type="info"}
This is not mandatory, you could also instantiate multiple managers and handle multiple licences concurrently. Just make sure you only use one manager instance per license, to avoid any issues.
:::

### LicenseManagementUI.cs - License Operations UI

This script controls the top portion of the UI for license operations:

**UI Elements:**

- License key input field
- Local files path display
- Activate button
- Deactivate button
- Delete local files button

**Key Functionality:**

- Collects license key input from user
- Triggers activation/deactivation operations
- Updates the local file path display
- Communicates with LicenseDetailsUI to refresh license info

### LicenseDetailsUI.cs - License Information Display

This script displays comprehensive license information and provides additional license operations:

**Displayed Information:**

- License key and type
- License status and validity
- Offline activation status
- Trial information
- Validity period and remaining days
- Grace period and maintenance period
- Last check timestamp
- Floating license details
- Consumption tracking (for usage-based licenses)
- Device variables

**Interactive Features:**

- **Check License:** Validates license with server
- **Borrow License:** Borrows a floating license for offline use
- **Sync Consumption:** Syncs usage data with server
- **Update Consumption:** Updates local consumption value
- **Add Device Variable:** Adds test device-specific data

### ProductDetailsUI.cs - Product Information Display

This script fetches and displays product information:

**Displayed Information:**

- Product name
- Product code
- Trial allowed (yes/no)
- Trial period duration (in days)
- Authorization type (license key, user-based, etc.)

**Functionality:**

- Loads product details from the SDK
- Displays them in the UI

### How They Work Together

Here's the flow of how these scripts interact:

```text
1. Unity starts → LicenseSpringManager.Awake() is called
   ↓
2. LicenseSpringManager.InitializeSdk() initializes the SDK with Config data
   ↓
3. UI scripts wait for initialization (using coroutines)
   ↓
4. Once initialized, ProductDetailsUI loads product information
   ↓
5. User enters license key in LicenseManagementUI
   ↓
6. User clicks "Activate" → LicenseManagementUI.OnActivateClicked()
   ↓
7. LicenseManagementUI calls LicenseSpringManager.ActivateLicense(key)
   ↓
8. On success, LicenseDetailsUI.UpdateLicenseInfo() refreshes the display
   ↓
9. User can now perform various operations (check, deactivate, borrow, etc.)
```

## 6. Configuration

To use the SDK with your own LicenseSpring account, you need to update the credentials in Config.cs.

### Opening Config.cs

1. In Unity Editor, go to the Project window
2. Navigate to: Assets > Scripts > Config.cs
3. Double-click to open in your code editor (Visual Studio or your preferred IDE)

### What to Update

Replace these values with your own credentials:

```csharp
private static readonly string ApiKey = "YOUR_API_KEY_HERE";
private static readonly string SharedKey = "YOUR_SHARED_KEY_HERE";
private static readonly string ProductCode = "YOUR_PRODUCT_CODE_HERE";
```

### Where to Get These Values

Log in to your LicenseSpring account at:

[**https://saas.licensespring.com/**](https://saas.licensespring.com/)

Navigate to:**&#x20;Settings -> Keys**

You'll find your API and Shared Key here.

### Hardware ID Algorithm Options

The SDK supports multiple algorithms for generating device fingerprints:

In `CreateExtendedOptions()`, you'll see:

```csharp
options.DeviceIdAlgorithm = LicenseSpring.DeviceIDAlgorithm.HardwareIdGeneratorWindowsHardwareFingerprintId;
```

Available options:

- `HardwareIdGeneratorWindowsHardwareFingerprintId` (recommended for Windows)
- `HardwareIdGeneratorWindowsUuid`
- `HardwareIdGeneratorMacOSSerialNumber`
- `HardwareIdGeneratorMacOSPlatformUuid`
- Multiple legacy algorithms

Choose the one that best fits your target platform(s).

### Local License File Storage

The SDK stores activated licenses locally in encrypted files. The storage location is configured in ExtendedOptions:

```csharp
options.LicenseFilePath = @"C:\Users\Username\AppData\Local\LicenseSpring\unity";
```

You can customize this path to any location. On different platforms, Unity will adjust the path accordingly:

- **Windows:** `C:\Users\[Username]\AppData\Local\LicenseSpring\unity`
- **macOS:** `~/Library/Application Support/LicenseSpring/unity`
- **Linux:** `~/.local/share/LicenseSpring/unity`

:::BlockQuote
**Note:** Use Unity's Application.persistentDataPath for cross-platform compatibility:
:::

```csharp
options.LicenseFilePath = System.IO.Path.Combine(Application.persistentDataPath, "LicenseSpring");
```

## 7. Running the Sample

### How to Enter Play Mode

1. Ensure SampleScene.unity is open (it should load automatically)
2. Click the Play button at the top center of the Unity Editor
3. The Game view will activate and show the sample application UI

### What Happens on Initialization

When you press Play, here's what happens behind the scenes:

1. Unity instantiates all GameObjects in the scene
2. `LicenseSpringManager.Awake()` is called immediately
3. `InitializeSdk()` runs, setting up the SDK with your configuration
4. UI scripts wait for initialization to complete
5. ProductDetailsUI loads and displays product information
6. The UI becomes interactive and ready for license operations

You'll see log messages in the Unity Console window showing the initialization progress.

### UI Walkthrough

The sample UI is organized into several sections:

**PRODUCT DETAILS**

- Product Name
- Product Code
- Trial Allowed
- Trial Period
- Authorization Type

**LICENSE MANAGEMENT**

- License Key Input Field
- \[Activate] \[Deactivate] buttons
- Local Files Path Display
- \[Delete Local Files] button

**LICENSE DETAILS**

- License Key
- License Type
- License Status
- Offline Activation Status
- Validity Period
- Days Remaining
- Last Checked
- Is Trial
- Floating License Info
- \[Check License] \[Borrow License] buttons

**CONSUMPTION TRACKING** (for usage-based licenses)

- Total Consumption
- Max Consumption
- \[Sync Consumption] \[Update Consumption] buttons

**DEVICE VARIABLES**

- Display of device-specific key-value pairs
- \[Add Device Variable] button

**To stop the sample:**
Click the Stop button to exit Play mode.

## 8. Testing Scenarios

This section provides step-by-step walkthroughs for testing different licensing scenarios.

***

### SCENARIO 1: Basic Online Activation

This is the most common scenario - activating a license with internet access.

**Steps:**

1. Click Play in Unity Editor to run the sample
2. Wait for the SDK to initialize (you'll see product details populate)
3. In the "License Key" input field, enter your test license key (You should have received this from your LicenseSpring account)
4. Click the \[Activate] button
5. If successful, you'll see:
   - License details populate with information
   - License status shows "Active"
   - Validity period and expiration date display
   - Days remaining shows the time left on the license
6. Check the Unity Console for detailed log messages

**What to Observe:**

- The license file is saved locally (path shown in "Local Files Path")
- The activated license persists between Play mode sessions
- Product features and restrictions are now enforced

***

### SCENARIO 2: License Checking and Validation

After activating a license, you can validate it with the server.

**Steps:**

1. Ensure you have an activated license (see Scenario 1)
2. Click the \[Check License] button in the License Details section
3. The SDK will contact the LicenseSpring server to validate:
   - License is still active
   - License hasn't been revoked
   - Device is still authorized
   - Any policy changes from the server
4. If valid, the license details refresh with updated information
5. The "Last Checked" timestamp updates to the current time

**What This Does:**

- Validates that the license is still active server-side
- Ensures the license hasn't been transferred to another device or in another way disabled
- Syncs any server-side changes
- Updates local license data with latest server information

**When to Use:**

- Periodically during application runtime (e.g., daily)
- When up to date server information is needed (e.g., floating licensing)
- Before enabling premium features
- After significant time offline

***

### SCENARIO 3: License Deactivation

Deactivating a license frees up an activation slot and removes local data.

**Steps:**

1. Ensure you have an activated license (see Scenario 1)
2. Click the \[Deactivate] button in the License Management section
3. The SDK will:
   - Contact the server to release the activation
   - Delete the local license file
   - Clear all license information from the UI
4. The activation slot is now available for another device
5. All license details fields will become empty
6. Click the \[Delete local files] button

**What to Observe:**

- The local license file is deleted (verify by checking the file path)
- The device is no longer counted against the max activations
- You can activate a different license key now

**Use Cases:**

- Transferring license to another device
- Testing different license configurations
- End of license period
- Application uninstallation

***

### SCENARIO 4: Floating License Borrowing/Release

Floating licenses allow temporary offline usage by "borrowing" a license.

**Prerequisites:**

- Your license must be a floating license type
- The license must have borrowing enabled

**Steps to Borrow:**

1. Activate a floating license (see Scenario 1)
2. Click the \[Borrow License] button
3. The SDK will reserve this license for your device
4. You can now use the application offline for the borrow period
5. The "Floating" status will indicate "Borrowed"

**Steps to Release (Return):**

1. Click the \[Borrow License] button again (it acts as a toggle)
2. The SDK returns the license to the floating pool
3. The license slot is now available for other concurrent users

**What This Enables:**

- Temporary offline usage
- Predetermined borrow period (configured in your LicenseSpring account)
- Ensures license returns to pool when no longer needed

**Floating License Timeout:**

If you don't interact with the application, the floating license will automatically timeout and return to the pool.

***

### SCENARIO 5: Consumption Tracking

For usage-based licensing (e.g., API calls, credits, processing time).

**Prerequisites:**

- Your license must be configured for consumption tracking
- The license must have a max consumption value set

**Steps to Update Consumption:**

1. Activate a license with consumption tracking enabled
2. In the Consumption section, note the "Total Consumption" and "Max Consumption"
3. Click \[Update Consumption] button
4. The local consumption value increments (simulating usage)
5. The "Total Consumption" field updates to reflect the new value

**Steps to Sync Consumption:**

1. Click \[Sync Consumption] button
2. The SDK sends the accumulated consumption data to the server
3. The server validates against the max consumption limit
4. If within limits, the sync succeeds
5. If over limit, the license may be restricted (depending on policy)

**What to Observe:**

- Consumption persists locally until synced
- The SDK can operate offline and sync later
- Server-side reporting shows usage analytics

**Use Cases:**

- API call credits
- Processing time tracking
- Feature usage limits
- Pay-per-use models

***

### SCENARIO 6: Device Variables

Device variables are custom key-value pairs stored with the license on the device.

**Steps:**

1. Activate a license (see Scenario 1)
2. Click \[Add Device Variable] button
3. A test device variable is added.
4. The device variable appears in the Device Variables display section
5. Device variables persist locally with the license file

**What This Enables:**

- Store device-specific configuration
- Track custom data per installation
- Implement feature flags per device
- Debug and support purposes

***

### SCENARIO 7: Working with Local License Files

Understanding how local license storage works.

**Viewing Local Files Path:**

1. Run the sample in Play mode
2. Look at the "Local Files Path" display in License Management section
3. Note the path (e.g., `C:\Users\[Username]\AppData\Local\LicenseSpring\[ProductKey]`)

**Inspecting License Files:**

1. Exit Play mode
2. Open Windows Explorer (or Finder on macOS)
3. Navigate to the path shown
4. You'll see encrypted license file (.lic)

**Deleting Local Files:**

1. In Play mode, click \[Delete Local Files] button
2. License file in that directory is removed
3. The application returns to an unlicensed state
4. You'll need to activate again to use the application

**What to Observe:**

- License files are encrypted
- Files persist between Play mode sessions
- Deleting files doesn't deactivate server-side (the activation slot remains used)
- To properly deactivate, always use the \[Deactivate] button first

**Testing Offline Behavior:**

1. Activate a license while online
2. Stop Play mode
3. Disconnect from the internet
4. Start Play mode again
5. The SDK loads the license from the local file
6. The application works offline (within grace period limits)

## 9. Customization Guide

### How to Integrate the SDK into Your Own Unity Project

This section explains how to take the LicenseSpring SDK and integrate it into your own Unity application.

### Step 1: Copy the DLLs Folder

1. In your UnitySample project, locate:

```text
Assets/Plugins/LicenseSpring/
```

1. Copy the entire LicenseSpring folder
2. In your own Unity project, paste it into:

```text
Assets/Plugins/LicenseSpring/
```

:::hint{type="info"}
Unity Automatically recognizes DLLs in the Plugins folder. Just drag and drop them in the folder and wait for the unity to initialize the files.
:::

:::hint{type="warning"}
It's possible you will need additional dlls not included with this demo, or that not all DLLs are needed, this depends on your specific SDK usage.
:::

### Step 2: Create Your Own Configuration

1. Create a new C# script in your project (e.g., `MyLicenseConfig.cs`)
2. Add your LicenseSpring credentials:

```csharp
public static class MyLicenseConfig
{
    private static readonly string ApiKey = "YOUR_API_KEY";
    private static readonly string SharedKey = "YOUR_SHARED_KEY";
    private static readonly string ProductCode = "YOUR_PRODUCT_CODE";

    public static LicenseSpring.Configuration CreateConfiguration()
    {
        var config = new LicenseSpring.Configuration(
            apiKey: ApiKey,
            sharedKey: SharedKey,
            productCode: ProductCode,
            appName: "YourAppName",
            appVersion: "1.0.0",
            extendedOptions: CreateExtendedOptions()
        );
        return config;
    }
    private static LicenseSpring.ExtendedOptions CreateExtendedOptions()
    {
        var options = new LicenseSpring.ExtendedOptions();
        options.CollectNetworkInfo = true;
        options.EnableLogging = true;
        options.DeviceIdAlgorithm = LicenseSpring.DeviceIDAlgorithm.HardwareIdGeneratorWindowsHardwareFingerprintId;
        // Any additional options
        return options;
    }
}
```

3. Customize ExtendedOptions as needed (logging, file paths, etc.)

### Step 3: Initialize the SDK

Create a manager script that initializes the SDK when your application starts:

```csharp
using LicenseSpring;
using UnityEngine;

public class MyLicenseManager : MonoBehaviour
{
    private ILicenseManager licenseManager;

    void Awake()
    {
        // Initialize SDK
        var config = MyLicenseConfig.CreateConfiguration();
        licenseManager = LicenseManager.GetInstance();
        licenseManager.Initialize(config);

        Debug.Log("LicenseSpring SDK initialized!");
    }

    public void ActivateLicense(string licenseKey)
    {
        try
        {
            var license = licenseManager.ActivateLicense(licenseKey);
            Debug.Log("License activated: " + license.GetLicenseKey());
        }
        catch (System.Exception ex)
        {
            Debug.LogError("Activation failed: " + ex.Message);
        }
    }

    public bool IsLicenseValid()
    {
        var license = licenseManager.CurrentLicense();
        return license != null && license.IsActive();
    }
}
```

Attach this script to a GameObject in your scene (e.g., a "LicenseManager" empty GameObject).

### Step 4: Implement License Checking in Your Application Flow

Decide where in your application you want to check the license:

- On application startup (in Awake or Start)
- Before enabling premium features
- Periodically during runtime
- Before critical operations

Example: Check license before starting the main application:

```csharp
public class ApplicationController : MonoBehaviour
{
    public MyLicenseManager licenseManager;

    void Start()
    {
        if (licenseManager.IsLicenseValid())
        {
            // Start main application
            LoadMainMenu();
        }
        else
        {
            // Show license activation UI
            ShowActivationDialog();
        }
    }
}
```

### Step 5: Persistence Considerations

The SDK automatically handles license persistence through local files. However, consider:

- Where to store license files (use \`Application.persistentDataPath)
- How often to check with the server (balance security vs. performance)
- Grace period configuration (allow temporary offline usage)
- How to handle license expiration gracefully in your UX

Example of configuring file path:

```csharp
var options = new LicenseSpring.ExtendedOptions();
options.LicenseFilePath = System.IO.Path.Combine(
    Application.persistentDataPath,
    "LicenseSpring"
);
```

### Best Practices

**1. Initialize Early**

- Initialize the SDK as early as possible in your application lifecycle
- Use `Awake()` or a `[RuntimeInitializeOnLoadMethod]` for earliest execution

**2. Handle Exceptions Gracefully**

- Wrap SDK calls in try-catch blocks
- Provide user-friendly error messages
- Log detailed errors for troubleshooting

**3. Check Licenses Periodically**

- Don't just check once at startup
- Periodically validate with the server

**4. Respect Offline Grace Periods**

- Allow users to work offline within configured grace periods
- Only enforce strict checks when online
- Provide clear messaging when license checks fail

**5. Test Different Scenarios**

- Test online activation
- Test offline behavior
- Test license expiration
- Test max activations reached
- Test invalid license keys

**6. Provide Clear User Feedback**

- Display clear error messages
- Explain why activation failed
- Provide support contact information

**7. Build Platform Considerations**

- Test on each target platform (Windows, macOS, Linux, Android, iOS)
- Verify file paths work cross-platform
- Ensure hardware ID generation works on all platforms
- Test IL2CPP builds (not just Mono)

## 10. Additional Information

### SDK Documentation

The `LicenseSpring.xml` file in `Assets/Plugins/LicenseSpring/` contains complete API documentation. This enables IntelliSense in Visual Studio and Rider.

**To view API docs:**

1. Open your C# script in Visual Studio
2. Type "LicenseSpring." and IntelliSense will show available classes
3. Hover over methods to see parameter descriptions and return types

### Main SDK Documentation

For comprehensive documentation, visit:

[**https://docs.licensespring.com/**](https://docs.licensespring.com/)

**Topics covered:**

- SDK installation and setup
- Advanced features (SSO, consumption, floating licenses)
- Best practices
- API reference
- Platform-specific guides

### Support

If you need assistance:

1. **Check the documentation at:** [**https://docs.licensespring.com/**](https://docs.licensespring.com/)
2. **Contact LicenseSpring Support:**
   - [**https://licensespring.zendesk.com/hc/en-us/requests/new**](https://licensespring.zendesk.com/hc/en-us/requests/new)
   - Include:
     - Unity version
     - Error messages from Console
     - Platform (Windows, macOS, etc.)
     - Steps to reproduce the issue
     - Please be as detailed as possible

### Sample Project Updates

The UnitySample project is maintained as part of the LicenseSpring .NET SDK repository. Check for updates periodically to get:

- Bug fixes
- New feature demonstrations
- Performance improvements
- Unity version updates

## Final Notes

Congratulations! You now have a comprehensive understanding of the LicenseSpring Unity SDK and the UnitySample project.

The LicenseSpring SDK provides powerful and flexible licensing for Unity applications. Take advantage of its features to protect your software and provide a great experience for your users.

**Happy licensing!** 🎉

[title] Air-Gapped
[path] Floating Server/Floating Server V1/License Options/

Air-gapped licenses are essential for systems that operate in secure or isolated environments without access to the internet. Below, we detail the processes for generating an airgap signature and adding an airgap license using the Floating Server API.&#x20;

It is important to understand the workflow of air-gapped licensing prior to this guide, please see [**our documented workflow**](https://docs.licensespring.com/license-entitlements/activation-types/air-gapped#R6s7d) and ensure this makes sense before continuing.

Specifically, the use of the floating server affects steps 4 and 7 only. **Steps 1-3, 5, 6 do not change**.

## Adding an Air-Gapped License With the API

This endpoint is used for activating the air-gapped license on the client-side, the final step of the air-gapped activation process. For more information on this API endpoint, see [**Add airgap license**](docId\:GVFTIPqb5LjYZZjQchLxQ).

## Adding an Air-Gapped License With User Interface

![Air-Gap License Activation on UI](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/PihyYHgcy9dT83eKuziJK_image.png "Air-Gap License Activation on UI")

### Generating Activation Code

Rather than completing this step in the client application, as explained on our main air-gap page, we enter this information and receive our activation code on the Floating Server. This process is seen on the left side of the above screenshot.

### Activating License on Client-Side

Rather than doing this on the SDK, the final step in the activation of the air-gapped license is inputting the confirmation code and activating it on the client-side. This is done on the right side of the above screenshot.

A full step-by-step guide on activating air-gapped licenses on the floating server can be found at [**Air-Gap License Activation**](docId\:Gu7iu9OlIugdXxM_YuXW-).

[title] Troubleshooting
[path] Floating Server/Floating Server V1/Deployment Methods/Docker/

If your questions are not answered on this page or within the [**FAQ**](docId\:z_8rL9S34hqoUKa58a23h), please [**submit a support ticket**](https://licensespring.zendesk.com/hc/en-us/requests/new) and our support team will respond as soon as possible!

### Issue: Missing or Incorrect Configuration File

**Solution**: Ensure that the `config.yaml` file is placed in the directory from which you are running the Docker container. The configuration file must include the correct settings, such as the database type (Redis or file-based) and API keys. Double-check that the path to the `config.yaml` file is correctly specified in the Docker Compose file:

```yaml
volumes:
  - ./config.yaml:/opt/server/config/config.yaml
```

### Issue: Redis Container Not Communicating with the Floating Server

**Solution**: Ensure both Redis and the Floating Server are running on the same Docker network. You can create a Docker network and connect both containers to it:

`docker network create fs-network`
`docker run -d --net fs-network --name redis -p 6379:6379 redis/redis-stack-server:latest`
`docker run -d --net fs-network --name floating-server -p 8080:8080 -v $PWD/config.yaml:/opt/server/config/config.yaml censedata/floating-server:latest`

### Issue: Redis Data Not Persisting After Container Restart

**Solution**: Ensure that a Docker volume is created and mounted to persist Redis data:

```yaml
volumes:
  - redis_data:/data
```

This ensures that data will be preserved even if the container is stopped or restarted.&#x20;

### Issue: Floating Server Not Accessible

**Solution**: Verify that the ports are correctly exposed in the Docker configuration. For example:

```yaml
ports:
  - "8080:8080"
```

This exposes the Floating Server on port 8080. Check your firewall and network settings to ensure the port is open.&#x20;

[title] Installation Steps
[path] Floating Server/Floating Server V1/Deployment Methods/Executable/

Below are the steps for deploying the Floating Server using executable files.

## **Step 1: Download the Executable**

Download the executable from [**this link**](https://floating-server.s3.eu-central-1.amazonaws.com/index.html) and unzip the file. After unzipping, you will find a directory named `web` and the executable file.

## **Step 2: Create the Configuration File**

The server requires a `config.yaml` file. This file is where you define the server settings, including the database and other optional parameters such as API URLs, product licenses, and login credentials.

### Example Configurations:

**Redis:**

```yaml
database:
  type: redis
  addresses: 
    - localhost:6379
```

**File-Based Database:**

```yaml
database:
  type: file
  addresses: 
    - database
```

This creates a `database` directory in the current location to store the data.

## Step 3: **Choose a Database**

Define the database type and address in your configuration file before running the server. You can choose between two database options:

1. **Redis:&#x20;**&#x41; fast, key-value database for efficient local storage.
2. **File-Based Database**: Embedded, suitable for Windows environments.

## Step 4: **Run the Executable**

Once your configuration file is in place, run the executable with the following:

Windows: `./floating-server.exe `

Linux: `./floating-server `

## **(Optional) Step 5: Customize the Run Command**&#x20;

You can customize how the server runs by specifying additional options, such as the port and configuration file path by customizing the run command.&#x20;

`./floating-server.exe -config /path/to/config.yaml `

For more information on configuring&#x20;

[title] Floating API
[path] SDKs/node.js SDK/

```typescript
class FloatingAPIv2 {

  constructor(config: FloatingAPIConfig);

  get tokenExpiryDate(): Dayjs;

  setLogLevel(level: LogLevel);

  getHardwareID(algorithm: HardwareIdAlgorithm = this.config.hardwareIDMethod ?? 0): string;
  
  async ping(): boolean;

  async authAddUser(user: User);

  async authChangePassword(body: ChangePasswordReq): boolean;

  async authInitialPassword(body: SetPasswordReq): boolean;

  async authLogin(body: LoginUser): LoginResponse;

  async authUsersList(): User[];

  async authUserDelete(id: number): boolean;

  async getConfig(): CloudConfig;

  async patchConfig(input: CloudConfigUpdate): boolean;

  async bundleActivate(body: BundleRequest): ActivateBundleResponse;

  async bundleDeactivate(id: number): DeactivateBundleResponse;

  async bundleOfflineActivationGenerate(body: OfflineRequestInput): GenerateOfflineRequestResponse;

  async bundleOfflineDeactivationGenerate(body: OfflineRequestInput): GenerateOfflineRequestResponse;

  async bundleOfflineActivationUpload(product: string, file: File | Blob): ActivateBundleResponse;

  async listLicenses(params?: { product?: string }): LicenseData[];

  async activateLicense(body: AddLicenseRequest): ActivateLicenseResponse;

  async getLicenseById(id: string): LicenseData;

  async deactivateLicense(id: number): boolean;

  async addLicenseConsumption(id: number, body: AddConsumptionRequest): ConsumptionResponse;

  async addFeatureConsumption(id: number, body: AddFeatureConsumptionRequest): FeatureConsumptionResponse;

  async listLicenseFeatureUsers(id: number): AllFeatureUsersResponse;

  async registerFeatureForUser(id: number, body: RegisterFeatureRequest): RegisterFeatureResponse;

  async releaseFeatureForUser(id: number, body: UnregisterFeatureRequest): boolean;

  async releaseFeatureForAllUsers(id: number, body: AllFeatureUsersRequest): FeatureReleasedAllResponse;

  async listLicenseUsers(id: number): FloatingUser[];

  async registerUserToLicense(id: number, body: RegisterRequestBody): LicenseData;

  async unregisterUserFromLicense(id: number, body: UsernameRequest): boolean;

  async unregisterAllUsersFromLicense(id: number): UnregisterAllUsersResponse;

  async borrowLicenseForUser(id: number, body: BorrowUserRequest): BorrowResponse;

  async offlineActivationGenerate(body: OfflineRequestInput): GenerateOfflineRequestResponse;

  async offlineActivationUpload(product: string, file: File | Blob): ActivateBundleResponse | ActivateLicenseResponse;

  async offlineDeactivationGenerate(body: OfflineRequestInput): GenerateOfflineRequestResponse;

  async airgapGenerateActivation(body: GenerateAirgapRequestBody): AirgapActivationCodeResponse;

  async airgapGenerateDeactivation(body: GenerateAirgapDeactivationRequestBody): AirgapDeactivationCodeResponse;

  async airgapDeactivate(body: DeactivateAirgapRequestBody): AirgapeDeactivatedResponse;

  async airgapActivate(file: File | Blob, jsonFile: File | Blob): AirgapActivatedResponse;

  async getSyncConfig(): SyncConfig;

  async setSyncMode(body: SyncEnableReq): boolean;

  async triggerSync(): boolean;
}

type FloatingAPIConfig = {
  apiPath: string,
  hardwareID?: string,
  hardwareIDMethod?: number,
  logLevel?: LogLevel,
  proxy?: AxiosProxyConfig,
  certChain: string,
  disableUserAuth?: boolean,
} & (
    {
      apiKey: string,
      sharedKey: string
    } | {
      clientID: string,
      clientSecret: string,
      tokenUrl: string
    }
  );
  
```

For declarations of types referenced here see: [**Type Declarations**](docId\:MZZqruPoqeqxNUuWSxNiZ)&#x20;

[title] License Options
[path] Floating Server/Floating Server V1/

The Floating Server supports a variety of license types, each tailored to different deployment environments and usage scenarios. Understanding these options will help you choose the most appropriate licensing method for your needs, ensuring optimal compliance and functionality.

Explore the following license types:

- **Online**:
  Requires an active internet connection to validate the licenses frequently. This option is suitable for environments where real-time license validation is feasible and necessary. Additional information can be found on the [**Online**](docId\:Mp97oEzkfYsO1k9CnRBcO) page.
- **Offline**:
  Designed for environments with no or limited internet connectivity. Offline licenses can be activated once and used without needing to connect to the internet, providing flexibility for remote or secure settings. More details are available on the [**Offline**](docId\:Eart7MueBAMUV6qpdsXR5) page.
- **Air-Gapped**:
  Specifically for environments that are completely isolated from the internet. These licenses are similar to offline licenses but tailored for setups where security and isolation are paramount. Visit the [**Air-Gapped**](docId\:LkwCIEpf4IL90uID7wymk) page for further information.
- **Hardware Key**:
  Utilizes physical devices (dongles) to manage license activation and validation. Hardware keys are highly secure and ideal for environments where software must be tightly controlled. Learn more on the [**Hardware Key**](docId:5VSC4S8pfXIbwHppAC0LI) page.
- **Which to Use?**:
  Not sure which license type is right for you? This section provides guidance based on your specific requirements and constraints, helping you make an informed decision. Check out the [**Which to Use?**](docId\:L0pEj6qp0QX5yrOXaB2xC) page for assistance.

Choosing the correct license type is crucial for ensuring your software’s integrity and compliance with licensing terms. Each type offers different benefits and is suited to particular scenarios, from tight security requirements to ease of use in various operational contexts.

[title] Connecting a Client
[path] Floating Server/Floating Server V1/

To connect a client to the Floating Server, you can register users, manage licenses, and track consumption through the API. While the API provides a flexible way to manage these tasks programmatically, the UI also offers insights and visibility into license usage and consumption.&#x20;

Starting from version 1.6.0, licenses are identified by **license IDs** after being added to the floating server. Previously, the **product code** was used to address a license.&#x20;

From version 1.6.0 onward:

- You can include **license IDs** in the body of requests to the floating server API to specify a particular license.
- If a license ID is not provided in the request, the **most recently added license** for the given product code will be addressed.

Prior to version 1.6.0:

- Only one license was supported per product code.
- As a result, there was no need to include a license ID in API requests.

## Registering a User

To register a new user on the Floating Server, use the API to send a POST request. The API allows you to provide details such as product code, license Id, user info, and host information.

- **API Endpoint**: /register
- **Full API Documentation**: [**Register user**](docId\:r9jsnoamyvLVnENPd1K9n)&#x20;

## Unregistering a User

You can remove a user from the system by sending an API request to unregister them. The server will remove the user's registration for the given product.

- **API Endpoint**: /unregister
- **Full API Documentation**: [**Unregister user**](docId\:kBS_ALXF6yhrUu7Roi41c)&#x20;

## Unregistering all Users of a Product

To quickly remove all users registered to a product, use the unregister/all API endpoint. This will clear all user registrations for a specific product.

- **API Endpoint**: /unregister/all
- **Full API Documentation**: [**Unregister all users**](docId\:nvRKTz-UpwRTq7tfFD0o2)&#x20;

## Borrowing a License Slot

If a user needs to "borrow" a license for use in an offline scenario, the API allows you to reserve a license slot for a user until a specific date.

- **API Endpoint**: /borrow
- **Full API Documentation**: [**Borrow license slot**](docId\:Yu2t9fVE-VJ2HVnCNwesw)&#x20;

### Client-Related Capabilities in the UI

The Floating Server's user interface also allows for easy management of client registrations, license usage, and consumption tracking without requiring API knowledge. For more information about the capabilities of the UI related to registrations, see [**Registrations**](docId:_RLZV-WhGCHEbhuvSU-Fx).

[title] Delphi SDK
[path] SDKs/Deprecated SDKs/

## Delphi SDK

- LicenseSpring Delphi libraries and LicenseSpring .Net SDK assembly
- Sample app project
- ReadMe file with installation instructions

[**LicenseSpringDelphiSDKv2.1.0.zip**](https://sdk-repo.s3.eu-west-1.amazonaws.com/LicenseSpringDelphiSDKv2.1.0.zip)

## Release Notes

### February 05, 2023, v2.1.0

- Updated LicenseSpring .NET SDK to v7.13.0
- Added wrappers for the grace period

### December 30, 2022, v2.0.0

- Updated wrappers with LicenseSpring .NET SDK v7.11.0
- Added license storage model implementation
- Added new classes
- Implemented API for device variables managing
- Implemented getting information on license users
- Updated sample
- Make SDK compatible with Delphi 11.2

### February 20, 2020, Initial Release

Based on the feature set from the .NET SDK v.5.4.0 release

[title] Local License
[path] SDKs/Go SDK/v2/Samples/

# Local License Check

The SDK provides the ability to perform a **local license check**, which validates the locally stored license file without communicating with the LicenseSpring server.

This function is especially useful in offline or air-gapped environments where no internet connection is available, or when you want to ensure the local license is still valid after restarting your application.

## What Does It Check?

When you call the local license check, the SDK performs several validations:

- Whether the license is **active** and **enabled**
- Whether the license is **expired**
- If the **device is authorized** to use the license
- If **system time manipulation** is detected (clock tampering)
- If the **product code matches**
- If the license is **floating**, whether its floating usage has expired
- (Optional) It verifies the **license signature**

```go
	license_data, check_resp, err := lh.LocalCheck(true)
	if err != nil {
		return err
	}
```

The true flag enables signature verification. You can set it to false if signature validation is not needed.

## Response Structure

The function returns a LocalCheckResponse:

```go
type LocalCheckResponse struct {
	LicenseResponse

	LicenseActive  bool `json:"license_active"`
	LicenseEnabled bool `json:"license_enabled"`
	IsExpired      bool `json:"is_expired"`

	DeviceLicensed  bool `json:"is_device_licensed"`
	IsClockTampered bool `json:"is_clock_tampered"`
	ProductMismatch bool `json:"product_mismatch"`
	FloatingExpired bool `json:"floating_expired"`
}
```

Use this response to determine whether the local license should be trusted.

## Get Current License

If your application restarts or you want to resume from the last known license state, you can load the locally stored license file using:

```go
	ld, err = lh.GetCurrentLicense()
	if err != nil {
		return err
	}
```

This retrieves the in-memory license data previously saved by the SDK.

## Notes

- Local checks do **not** validate or sync with the cloud.
- Use `LocalCheck` to determine license validity before performing actions that depend on license state.


[title] license
[path] Floating Server/Floating Server V1/API Reference/


[title] Installation Steps
[path] Floating Server/Floating Server V1/Deployment Methods/Docker/

Deploying the Floating Server with Docker provides a flexible way to manage the server in isolated containers.&#x20;

Below are the steps to deploy the Floating Server using Docker.

1. **Download the Docker Image**:
   Pull the Docker image from Docker Hub:
   - `docker pull censedata/floating-server:latest`
2. **Create a Docker Network and Redis Volume:**
   To ensure smooth communication between Redis and the Floating Server, set up a Docker network and volume:&#x20;
   - `docker network create fs-network`
   - `docker volume create redis`
3. **Run Redis in a Docker Container:**
   Run Redis to serve as the database for the Floating Server:&#x20;
   - `docker run -d --net fs-network --name redis -p 6379:6379 -v redis:/data redis/redis-stack-server:latest`
4. **Create a Configuration File**
   Docker requires a `config.yaml` file for the server to operate. Place the `config.yaml` file in the directory where you will run the Docker container. For more details on configuration options, visit the [**Configuration File**](docId\:QHWax01fYGKmU_ApnXZ2A) section.
5. **Run the Floating Server in Docker**
   Launch the Floating Server by mounting the configuration file in the container:&#x20;
   - `docker run -d --net fs-network --name floating-server -p 8080:8080 -v $PWD/config.yaml:/opt/server/config/config.yaml censedata/floating-server:latest`


[title] Troubleshooting
[path] Floating Server/Floating Server V1/Deployment Methods/Kubernetes (Helm)/

If your questions are not answered on this page or within the [**FAQ**](docId\:z_8rL9S34hqoUKa58a23h), please [**submit a support ticket**](https://licensespring.zendesk.com/hc/en-us/requests/new) and our support team will respond as soon as possible!

### Issue: Helm Chart Deployment Fails

**Solution**: Ensure that all required configuration values are properly set in your Helm values file. This includes specifying the database type (Redis) and ensuring your Kubernetes cluster has sufficient resources for the deployment. You can inspect the logs of the failing pods with:

`kubectl logs <pod-name>`

### Issue: Redis Not Connecting to Floating Server

**Solution**: Verify that Redis and the Floating Server are deployed in the same namespace and that Redis is reachable from the Floating Server. Check the service definitions and ensure that the Redis service is properly exposing its ports:

```yaml
ports:
  - port: 6379
```

### Issue: Data Not Persisting in Redis

**Solution**: Ensure that a persistent volume claim (PVC) is set up for Redis to store data across restarts. Check your Helm values file to confirm the PVC is defined:

```yaml
persistence:
  enabled: true
  storageClass: <your-storage-class>
  accessModes:
    - ReadWriteOnce
  size: 1Gi
```

### Issue: Floating Server Not Accessible

**Solution**: Make sure that the Kubernetes service for the Floating Server is correctly exposing the port. Use the following command to check the service configuration:

`kubectl get svc <floating-server-service>`

Ensure that the correct port is exposed and accessible from outside the cluster.&#x20;

[title] License Manager
[path] SDKs/node.js SDK/

## LicenseManager

Provides a high-level interface for managing licenses, including local licenses. The LicenseManager is required to work with local license files. Typescript definitions are provided for the arguments and return types of the class methods.

To import the LicenseManager class use:

```javascript
const { LicenseManager } = require('@licensespring/node-sdk');
```

To create an instance:

```javascript
const licenseManager = new LicenseManager({
  apiKey: '12345678-4bfe-4e3a-8737-757004d6294c',
  sharedKey: 'eYuHrlajvIVTiSFIXpxpKhw78f4Ewy-00-12345678',
  appName: 'js-sdk-test-1',
  appVersion: '0.0.1',
  productCode: 'lkp',
  /** NOTE: the following properties are set to their default values by the SDK and can be overriden manually: */
  // apiPath: 'http://api.dev.licensespring.com/api/v4',
  // publicKey: '...',
});
```

The constructor takes the a single argument of the following type:

```typescript
{
  /** your Licensespring API key */
  apiKey: string,
  /** your Licensespring API Shared key **/
  sharedKey: string,
  /** custom name for your application */
  appName: string,
  /** custom version string for your application */
  appVersion: string,
  /** your product short code */
  productCode: string,
  /** your Air Gap Activation key (optional) */
  airGapKey?: string,
  /** override for License API url (default is https://api.licensespring.com/api/v4/) **/
  apiPath?: string,
  /** override for License API public key (default is pub key for api.licensespring.com) **/
  publicKey?: string,
  /** override for License File filename (default is "License") */
  filename?: string,
  /** override for License File path (default is current directory) */
  filePath?: string,
  /** override for License File encryption key */
  fileKey?: string,
  /** override for license grace period duration in hours (default is 24) */
  gracePeriod?: number,
  /** override for License File guard file (default is false) */
  isGuardFileEnabled?: boolean,
  /** override for Hardware ID calculation method (default is 0, for more info see "Hardware ID" section) */
  hardwareIDMethod?: number,
  /** a custom provided Hardware ID (overrides HWID calculation) */
  hardwareID?: string,
}
```

## Methods

Methods listed here which take a license payload are the similar to corresponding methods in the License API class, except that `product` and `hardware_id` do not have to be specified in the payload as they are provided by the License Manager object.

### Check License

See: [**Check License**](docId\:Zh4KFIh_s59TzIBZKeb9o)&#x20;

```typescript
checkLicense(
  payload: CheckLicensePayload, 
  includeExpiredFeatures: boolean = false
): Promise<CheckLicenseResponse>

type CheckLicensePayload = ({
  username: string;
} | {
  license_key: string;
}) & {
  env: string | undefined;
  license_id: number | undefined;
  sdk_ver: string | undefined;
  app_ver: string | undefined;
  hostname: string | undefined;
  os_hostname: string | undefined;
  ip_local: string | undefined;
  mac_address: string | undefined;
  ip: string | undefined;
  os_ver: string | undefined;
  channel: string | undefined;
};

type CheckLicenseResponse = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  allow_offline_activation: boolean,
  can_borrow: boolean,
  custom_fields: CustomField[],
  customer: CustomerResponse,
  enable_maintenance_period: boolean,
  floating_timeout: number,
  floating_users?: number,
  grace_period: number | null,
  is_air_gapped: boolean,
  is_floating: boolean,
  is_floating_cloud: boolean,
  is_hardware_key_auth: boolean,
  license_key: string | undefined,
  license_template_id?: number,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users?: number,
  max_overages: number,
  max_transfers?: number,
  metadata: JSONObjectRequired,
  metadata_string?: string,
  order_store_id?: string,
  prevent_vm: boolean,
  company: {
    id: number,
  },
  product_details?: ProductDetailsResponse,
  product_features: FeatureResponse[],
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null,
  is_trial: boolean,
  trial_days?: number,
  user?: LicenseUserResponse,
  license_type: LicenseTypes,
  allow_negative_consumptions?: boolean,
  allow_unlimited_consumptions?: boolean,
  consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
  max_consumptions?: number,
  reset_consumption?: boolean,
  total_consumptions?: number,
  borrowed_until: string | null,
  floating_in_use_devices?: number,
  is_borrowed: boolean,
  is_expired: boolean,
  license_active: boolean,
  license_enabled: boolean,
  license_signature: string,
};
```

### Activate License Online

See: [**Activate License (Online Method)**](docId\:Mt2yGm6CJzh2bumU-Gfww)&#x20;

```typescript
activateLicense(payload: ActivateLicensePayload): Promise<ActivateLicenseResponse>

type ActivateLicensePayload = ({ 
  license_key: string; 
} | {
  username: string;
  password: string;
} | {
  code: string;
  customer_account_code: string;
} | {
  id_token: string;
  customer_account_code: string;
}) & {
  variables: { [key: string]: string | number | boolean } | undefined;
};

type ActivateLicenseResponse = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  allow_offline_activation: boolean,
  can_borrow: boolean,
  custom_fields: CustomField[],
  customer: CustomerResponse,
  enable_maintenance_period: boolean,
  floating_timeout: number,
  floating_users?: number,
  grace_period: number | null,
  is_air_gapped: boolean,
  is_floating: boolean,
  is_floating_cloud: boolean,
  is_hardware_key_auth: boolean,
  license_key: string | undefined,
  license_template_id?: number,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users?: number,
  max_overages: number,
  max_transfers?: number,
  metadata: JSONObjectRequired,
  metadata_string?: string,
  order_store_id?: string,
  prevent_vm: boolean,
  company: {
    id: number,
  },
  product_details?: ProductDetailsResponse,
  product_features: FeatureResponse[],
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null,
  is_trial: boolean,
  trial_days?: number,
  user?: LicenseUserResponse,
  license_type: LicenseTypes,
  allow_negative_consumptions?: boolean,
  allow_unlimited_consumptions?: boolean,
  consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
  max_consumptions?: number,
  reset_consumption?: boolean,
  total_consumptions?: number,
  request: string,
  active: boolean,
  device_id: number,
  validity_period: string | null,
  is_expired: boolean,
  hardware_id: string,
  username?: string,
  max_license_users?: number,
  is_floating_cloud: boolean,
  floating_in_use?: boolean,
  license_signature: string,
  variables?: ({
    value: string;
    device_id: number;
    variable: string;
    created_at: string | null;
  })[];
};
```

### Deactivate License Online

See: [**Deactivate License (Online Method)**](docId\:IEcDUEuMOsLwN4biictdc)&#x20;

```typescript
deactivateLicense(payload: ({  
  username: string;
} | {
  license_key: string;
}): Promise<boolean>
```

### Activate License Offline

See: [**Activate License (Offline Method)**](docId\:H_VEWmE7rYJ7QfbIKvGuP)&#x20;

```typescript
activateOffline(payload: string): Promise<ActivateOfflineResponse>

type ActivateOfflineResponse = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  allow_offline_activation: boolean,
  can_borrow: boolean,
  custom_fields: CustomField[],
  customer: CustomerResponse,
  enable_maintenance_period: boolean,
  floating_timeout: number,
  floating_users?: number,
  grace_period: number | null,
  is_air_gapped: boolean,
  is_floating: boolean,
  is_floating_cloud: boolean,
  is_hardware_key_auth: boolean,
  license_key: string | undefined,
  license_template_id?: number,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users?: number,
  max_overages: number,
  max_transfers?: number,
  metadata: JSONObjectRequired,
  metadata_string?: string,
  order_store_id?: string,
  prevent_vm: boolean,
  company: {
    id: number,
  },
  product_details?: ProductDetailsResponse,
  product_features: FeatureResponse[],
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null,
  is_trial: boolean,
  trial_days?: number,
  user?: LicenseUserResponse,
  license_type: LicenseTypes,
  allow_negative_consumptions?: boolean,
  allow_unlimited_consumptions?: boolean,
  consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
  max_consumptions?: number,
  reset_consumption?: boolean,
  total_consumptions?: number,
  request: string,
  active: boolean,
  device_id: number,
  validity_period: string | null,
  is_expired: boolean,
  hardware_id: string,
  username?: string,
  max_license_users?: number,
  is_floating_cloud: boolean,
  floating_in_use?: boolean,
  license_signature: string,
  variables?: ({
    value: string;
    device_id: number;
    variable: string;
    created_at: string | null;
  })[];
  date: string,
  offline_signature: string,
  license_signature_v2: string,
};
```

### Deactivate License Offline

Performs an offline deactivation

```typescript
deactivateOffline(): Promise<boolean>
```

### Get Trial Key

See: [**Trial Key**](docId\:MtAnOsFYJyXU-2M0OVz_a)&#x20;

```typescript
getTrialKey(payload: GetTrialKeyPayload): Promise<TrialResponse>

type GetTrialKeyPayload = {
    sdk_ver: string | undefined;
    email: string | undefined;
    license_policy: string | undefined;
    first_name: string | undefined;
    last_name: string | undefined;
    phone: string | undefined;
    address: string | undefined;
    postcode: string | undefined;
    state: string | undefined;
    country: string | undefined;
    city: string | undefined;
    reference: string | undefined;
    company_name: string | undefined;
};

type TrialResponse = TrialExistingResponse | TrialNewResponse;

type TrialExistingResponse = {
  license_type: LicenseTypes,
  is_trial: boolean,
  license: string,
} | {
  license_type: LicenseTypes,
  is_trial: boolean,
  license_user: string,
};

type TrialNewResponse = {
  id: number;
  order_id: number;
  product_id: number;
  created_at: number;
  updated_at: number;
  active: boolean;
  enable_maintenance_period: boolean;
  enabled: boolean;
  is_floating: boolean;
  is_hardware_key_auth: boolean;
  is_trial: boolean;
  license_type: LicenseTypes;
  maintenance_duration: string | null;
  max_activations: number;
  max_transfers: number;
  metadata_string: string | undefined;
  metadata: JSONObjectRequired,
  prevent_vm: boolean;
  times_activated: number;
  trial_days: number;
  validity_period?: string;
  company: {
    id: number;
  };
  LicenseProductFeatures: ({
    id: number;
    product_feature_id: number;
    max_consumption: number;
    allow_overages: boolean;
    max_overages: number;
    reset_consumption: boolean;
    consumption_period?: ConsumptionPeriod;
    is_floating: boolean;
    is_floating_cloud: boolean;
    metadata: JSONObjectRequired,
    metadata_string?: string;
    floating_timeout?: number;
    floating_users?: number;
  })[];
  LicenseCustomFields: ({
    product_custom_field_id: number;
    value: string | undefined;
  })[];
  is_floating_cloud: boolean;
  floating_users: number;
  floating_timeout: number;
  allow_overages: boolean;
  max_overages: number;
  max_consumptions: number;
  valid_duration: null;
  consumption_period: ConsumptionPeriod | null;
  reset_consumption?: boolean;
  grace_period: number;
  allow_grace_period: boolean;
} & ({
  license: string;
  license_key: string;
} | {
  license_user: string;
  initial_password: string;
  license_user_id: number | null;
  max_license_users: number;
});
```

### List Licenses for User

See: [**Licenses for User**](docId\:rP314yS1TvcYmB99k7UuV)&#x20;

```typescript
getUserLicenses(payload: GetUserLicensesPayload): Promise<GetUserLicensesResponse>

type GetUserLicensesPayload = { 
  license_key: string; 
} | {
  username: string;
  password: string;
} | {
  code: string;
  customer_account_code: string;
} | {
  id_token: string;
  customer_account_code: string;
};

type GetUserLicensesResponse = ({
  
  license: {
    id: number,
    allow_grace_period: boolean,
    allow_overages: boolean,
    allow_unlimited_activations: boolean,
    allow_offline_activation: boolean,
    can_borrow: boolean,
    custom_fields: CustomField[],
    customer: CustomerResponse,
    enable_maintenance_period: boolean,
    floating_timeout: number,
    floating_users?: number,
    grace_period: number | null,
    is_air_gapped: boolean,
    is_floating: boolean,
    is_floating_cloud: boolean,
    is_hardware_key_auth: boolean,
    license_key: string | undefined,
    license_template_id?: number,
    maintenance_period: string | null,
    max_activations: number,
    max_borrow_time: number,
    max_license_users?: number,
    max_overages: number,
    max_transfers?: number,
    metadata: JSONObjectRequired,
    metadata_string?: string,
    order_store_id?: string,
    prevent_vm: boolean,
    company: {
      id: number,
    },
    product_details?: ProductDetailsResponse,
    product_features: FeatureResponse[],
    start_date: string | null,
    times_activated: number,
    transfer_count: number,
    validity_period: string | null,
    is_trial: boolean,
    trial_days?: number,
    user?: LicenseUserResponse,
    license_type: LicenseTypes,
    allow_negative_consumptions?: boolean,
    allow_unlimited_consumptions?: boolean,
    consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
    max_consumptions?: number,
    reset_consumption?: boolean,
    total_consumptions?: number,
    license_active: boolean,
    license_enabled: boolean,
  },
  
  user: {
    id: number,
    email: string,
    first_name: string,
    is_initial_password: boolean,
    last_name: string,
    phone_number: string,
    allow_unlimited_activations?: boolean,
    max_activations?: number,
    total_activations?: number,
  },
})[];
```

### List License Users for Customer

See: [**List License Users for Customer**](docId\:m4Gokma1PFwxAdK0cgLKl)&#x20;

```typescript
getCustomerLicenseUsers(payload: {
    customer: string;
}): Promise<CustomerLicenseUsersResponse>

type CustomerLicenseUsersResponse = {
  company: {
    id: number;
  };
  customer: CustomerResponse;
  users: ({
    email: string | undefined;
    allow_unlimited_activations: boolean;
    first_name: string;
    initial_password: string;
    is_active: boolean;
    is_initial_password: boolean;
    last_name: string;
    license_id: number;
    max_activations: number;
    order_id: number;
    order_store_id: string;
    phone_number: string;
    total_activations: number;
  })[];
};
```

### Check License Feature

See: [**License Feature Check**](docId\:NOL8JafP0APIA6Di6W5vT)&#x20;

```typescript
checkLicenseFeature(payload: CheckLicenseFeaturePayload): Promise<CheckLicenseFeatureResponse>

type CheckLicenseFeaturePayload = ({
  license_key: string;
} | {
  username: string;
}) & {
  license_id: number | undefined;
  sdk_ver: string | undefined;
  include_metadata_string: boolean | undefined;
  feature: string;
};

type CheckLicenseFeatureResponse = {
  id: number;
  license_id: number;
  code: string;
  name: string;
  metadata: JSONObjectRequired,
  metadata_string?: string;
  is_floating: boolean;
  is_floating_cloud: boolean;
  floating_in_use_devices?: number;
  expiry_date: string | null;
  feature_type: 'activation';
} | {
  id: number;
  license_id: number;
  code: string;
  name: string;
  metadata: JSONObjectRequired,
  metadata_string?: string;
  is_floating: boolean;
  is_floating_cloud: boolean;
  floating_in_use_devices?: number;
  expiry_date: string | null;
  feature_type: 'consumption';
  consumption_period: ConsumptionPeriod;
  allow_negative_consumptions: boolean;
  allow_overages: boolean;
  allow_unlimited_consumptions: boolean;
  max_consumption: number;
  max_overages: number;
  reset_consumption: boolean;
  total_consumptions: number;
};
```

### Add License Consumption

See: [**Add Consumption**](docId\:SRwB9sGGWhqXqncym3TBi)&#x20;

```typescript
addConsumption(payload: AddConsumptionPayload): Promise<AddConsumptionResponse>

type AddConsumptionPayload = ({
  license_key: string | undefined;
} | {
  username: string | undefined;
}) & {
  consumptions: number;
  sdk_ver: string | undefined;
  license_id: number | undefined;
  ignore_events: boolean | undefined;
  allow_overages: boolean | undefined;
  max_overages: number | undefined;
  event: ("consumption_add" | "offline_floating_consumptions_sync")[] | undefined;
};

type AddConsumptionResponse = {
  id: number;
  max_consumptions: number;
  allow_unlimited_consumptions: boolean;
  allow_negative_consumptions: boolean;
  allow_overages: boolean;
  max_overages: number;
  reset_consumption: boolean;
  consumption_period: ConsumptionPeriod | undefined;
  total_consumptions: number;
  company: {
    id: number;
  };
};
```

### Add Feature Consumption

See: [**Add Feature Consumption**](docId\:VP8t3pHTtDPQ46i9YKtFF)&#x20;

```typescript
addFeatureConsumption(payload: AddFeatureConsumptionPayload): Promise<AddFeatureConsumptionResponse>

type AddFeatureConsumptionPayload = ({
  license_key: string | undefined;
} | {
  username: string | undefined;
}) & {
  consumptions: number;
  feature: string;
  sdk_ver: string | undefined;
  license_id: number | undefined;
  ignore_events: boolean | undefined;
  allow_overages: boolean | undefined;
  max_overages: number | undefined;
  event: ("consumption_add" | "offline_floating_consumptions_sync")[] | undefined;
};

type AddFeatureConsumptionResponse = {
  id: number;
  license_id: number;
  company: {
    id: number;
  };
  total_consumptions: number;
  max_consumptions: number;
  allow_negative_consumptions: boolean;
  allow_unlimited_consumptions: boolean;
  allow_overages: boolean;
  max_overages: number;
  reset_consumption: boolean;
  consumption_period: ConsumptionPeriod;
  is_floating: boolean;
  is_floating_cloud: boolean;
  floating_timeout?: number;
  floating_users?: number;
};
```

### Get Product Details

See: [**Get Product Details**](docId\:AR0IgR0c1_Dvx1yn044RR)&#x20;

```typescript
getProductDetails(payload: ProductDetailsPayload): Promise<GetProductDetailsResponse>

type ProductDetailsPayload = {
    include_latest_version: boolean | undefined;
    include_custom_fields: boolean | undefined;
    env: string | undefined;
};

type GetProductDetailsResponse = {
  product_id: number,
  product_name: string,
  short_code: string,
  allow_trial: boolean,
  trial_days: number,
  authorization_method: AuthorizationMethod,
  floating_timeout: number,
  allow_overages: boolean,
  max_overages: number,
  prevent_vm: boolean,
  metadata: JSONObjectRequired,
  metadata_string?: string,
  company: {
    id: number
  },
  latest_version?: {
    id: number;
    version: string | undefined;
    full_link: string | undefined;
    filename: string | undefined;
    release_date: string | null;
    hash_md5: string | undefined;
    environment: string;
    eula_link: string | undefined;
    release_notes_link: string | undefined;
    size: string | undefined;
    requires_version: string | undefined;
    channel: string | undefined;
    created_at: string | null;
    updated_at: string | null;
    enabled: boolean;
    product_id: number;
  } | null,
  custom_fields?: { id: number, name: string, default_value: string }[]
};
```

### Get Device Variables

See: [**Get Device Variables**](docId\:ZjVswpdxa3gR_9kIq0Gng)&#x20;

```typescript
getDeviceVariables(payload: GetDeviceVariablesPayload): Promise<GetDeviceVariablesResponse>

type GetDeviceVariablesPayload = ({
    license_key: string;
} | {
    username: string;
}) & {
    sdk_ver: string | undefined;
    license_id: number | undefined;
};

type GetDeviceVariablesResponse = {
  id: number;
  created_at: string;
  variable?: string;
  value?: string;
  device_id: number;
}[];
```

### Track Device Variables

See: [**Track Device Variables**](docId:9lCvdjjD_nsJUu7UibEaA)&#x20;

```typescript
trackDeviceVariables(payload: TrackDeviceVariablesPayload): Promise<TrackDeviceVariablesResponse>

type TrackDeviceVariablesPayload = ({
    license_key: string;
} | {
    username: string;
}) & {
    variables: { [key: string]: string | number | boolean },
    sdk_ver: string | undefined;
    license_id: number | undefined;
};

type TrackDeviceVariablesResponse = {
  variable: string;
  value: string;
  device_id: number;
  created_at: number;
}[];
```

### Borrow Floating License

See: [**Borrow Floating License**](docId\:SoOypvnWqodzw1rTwyuST)&#x20;

```typescript
floatingBorrow(payload: FloatingBorrowPayload): Promise<FloatingBorrowResponse>

type FloatingBorrowPayload = ({
    license_key: string;
} | {
    username: string;
    password: string;
}) & {
    borrowed_until: string | null;
    sdk_ver: string | undefined;
    license_id: number | undefined;
};

type FloatingBorrowResponse = {
  borrowed_until: string | null;
  max_borrow_time: number;
  device_id: number;
  license_id: number;
  company: {
    id: number;
  };
};
```

### Release Floating License

See: [**Release Floating License**](docId\:Ac4QjdmMGxWJRZJv9mRrU)&#x20;

```typescript
floatingRelease(payload: FloatingReleasePayload): Promise<boolean>

type FloatingReleasePayload = ({
    license_key: string;
} | {
    username: string;
}) & {
    sdk_ver: string | undefined;
    license_id: number | undefined;
};
```

### Release Floating Feature

See: [**Release Floating Feature**](docId\:VySqAv5zovSK4Lj93xVDi)&#x20;

```typescript
featureRelease(payload: FloatingFeatureReleasePayload): Promise<boolean>

type FloatingFeatureReleasePayload = ({
    license_key: string;
} | {
    username: string;
}) & {
    feature: string;
    sdk_ver: string | undefined;
    license_id: number | undefined;
};
```

### Change Password

See: [**Change Password**](docId\:B4ixyzvAh4TAltTuuajyi)&#x20;

```typescript
changePassword(payload: {
    username: string;
    password: string;
    new_password: string;
}): Promise<boolean>
```

### Get Product Versions

See: [**Get Product Versions**](docId\:mBq0eK4XlT_jX8SLdyHY9)&#x20;

```typescript
getVersions(payload: GetVersionsPayload): Promise<VersionsResponse>

type GetVersionsPayload = ({
    license_key: string;
} | {
    username: string;
}) & {
    sdk_ver: string | undefined;
    env: string | undefined;
    channel: string | undefined;
};

type VersionsResponse = ({
  version: string | undefined;
  release_date: string | null;
})[];
```

### Get Product Installation File

See: [**Get Installation File**](docId\:LxPe6kV-OLj7HLL-GrL1q)&#x20;

```typescript
getInstallationFile(payload: GetInstallationFilePayload): Promise<InstallationFileResponse>

type GetInstallationFilePayload = ({
    license_key: string;
} | {
    username: string;
}) & {
    sdk_ver: string | undefined;
    env: string | undefined;
    channel: string | undefined;
    version: string | undefined;
};

type InstallationFileResponse = {
  id: number;
  version: string | undefined;
  installation_file: string | undefined;
  release_date: string | null;
  hash_md5: string | undefined;
  environment: string;
  eula_link: string | undefined;
  release_notes_link: string | undefined;
  size: string | undefined;
  requires_version: string | undefined;
  channel: string | undefined;
  company: {
    id: number;
  };
};
```

### Get Single Sign-On URL

See: [**Single Sign-On URL**](docId\:QbJwnphsDcS0L25UW6PTq)&#x20;

```typescript
getSSOUrl(payload: {
    response_type: 'token' | 'code' | undefined;
    product: string;
    customer_account_code: string;
}): Promise<SSOUrlResponse>

type SSOUrlResponse = {
  url: string;
  openid_configuration: {
    [key: string]: string | number | boolean;
  };
};
```

### Air-Gapped Licenses

[**https://docs.licensespring.com/license-entitlements/activation-types/air-gapped**](https://docs.licensespring.com/license-entitlements/activation-types/air-gapped)

```typescript
getAirGapActivationCode(initializationCode: string, licenseKey: string)
```

Performs verifyConfirmationCode and activates Air-Gapped License:

```typescript
activateAirGapLicense(confirmationCode: string, licenseKey: string, policyFilePath: string, policyID: string)
```

### License Utility Methods

The following methods on the LicenseManager class take a single argument which is the license object returned from a license activation, a license check or parsed from the license file.

Checks if License is enabled, active and not expired:

```typescript
isValid(license: {
    license_active: boolean,
    license_enabled: boolean,
    validity_period: DateISO8601UTC | null,
  }): boolean
```

Returns days remaining in maintenance period:

```typescript
maintenanceDaysRemaining(license: {
    enable_maintenance_period: boolean
    maintenance_period: string | null,
  }): number
```

Returns days remaining in license validity period:

```typescript
daysRemaining(license: {
    grace_period: number,
    validity_period: DateISO8601UTC | null,
  }): number
```

### License File

See [**License File**](https://www.npmjs.com/package/@licensespring/node-sdk#license-file)

```typescript
/** Reads and parses the local license file and returns its data as a License object */
loadLicense(): License

/** Verifies the local license file's integrity */
isLicenseFileCorrupted(): boolean

/** Deletes the local license file and guard file */
clearLocalStorage(): void
```

##


[title] Consumption List
[path] Floating Server/Floating Server V1/User Interface/Registrations/

## Consumptions

The floating server provides support for managing license and feature consumptions associated with the licenses stored within its database. Requests to add consumptions are handled through the `/add_consumption` and `/add_feature_consumption` endpoints. Upon receipt of these requests, provided there are sufficient consumptions available for the specific license or feature, the floating server immediately updates the local consumption value. This updated value is reflected in the server's response as well as displayed on the UI's registration page.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Vzm0OLucwwaKIBt3TkNMs_image.png)

Additionally, at hourly intervals, local consumption values of hte platform-sourced licenses undergo synchronization with the cloud LicenseSpring server. Detailed insights into both license and feature consumptions, including maximum allowed consumption and overages, can be found on the license details page, accessible from the configuration page.

It's essential to note that any alteration to a consumption value requires the license or feature to be of consumption type and that sufficient consumption is available, taking into account maximum consumption limits, overages allowance, and the possibility of unlimited consumption.

:::ApiMethodV2
```json
{
  "name": "Add Consumption",
  "method": "POST",
  "url": "/api/v4/add_consumption",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "q_dqrECSJj9iADEqD5aL3",
        "language": "go",
        "code": "url := sourceURL + \"add_consumption\"\n\ndata := Consumption{\n\tProduct:        product,\n\tConsumptions:   consumptions,\n\tMax_overages:   max_overages,\n\tAllow_overages: allow_overages,\n}\n\nupdatedJSON, err := json.Marshal(data)\n\nreq, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(updatedJSON))\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "q_dqrECSJj9iADEqD5aL3"
  },
  "results": {
    "languages": [
      {
        "id": "L3LCzcQMorw9PjBBNVe9z",
        "language": "200",
        "customLabel": "",
        "code": "{\n    \"max_consumptions\":100,\n    \"total_consumptions\":1,\n    \"allow_overages\":false,\n    \"max_overages\":0,\n    \"reset_consumption\":true,\n    \"consumption_period\":\"daily\",\n    \"allow_unlimited_consumptions\":false\n}"
      },
      {
        "id": "SXLuK8oAjwcqlO--SMIn0",
        "language": "400",
        "code": "{\n    \"code\":\"license_activated_max_times\",\n    \"message\":\"No free slots for product p1\",\n    \"status\":400\n}",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "L3LCzcQMorw9PjBBNVe9z"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "Product",
        "kind": "required",
        "type": "string",
        "description": "Product Short Code"
      },
      {
        "name": "Consumptions",
        "kind": "required",
        "type": "string",
        "description": "Number of Consumptions",
        "children": []
      },
      {
        "name": "Max_overages",
        "kind": "optional",
        "type": "string",
        "description": "Maximum Number of Overages",
        "children": []
      },
      {
        "name": "Allowe_overages",
        "kind": "optional",
        "type": "string",
        "description": "True or False",
        "children": []
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "add-consumption",
  "legacyHash": "wUdrt-iOkqfEeTQXCiSoc"
}
```
:::

## Consumption Reset

For licenses or features designated for consumption reset with defined consumption periods, consumption values are automatically reset to zero by the end of this period. This reset occurs during one of the hourly synchronization events. Consequently, it may take up to an hour following the reset period for this adjustment to reflect on the server. Consumption reset periods can be opted between daily, weekly, monthly, or annually.

[title] Consumption License
[path] SDKs/Go SDK/v2/Samples/

Licenses of type **consumption** allow you to use a limited or unlimited number of consumable units, which can be applied based on your application’s needs. For example,&#x20;

Our SDK provides a simple two-step process for managing consumptions:

1. **Local Consumption** – You update the locally stored license file to reflect usage, without communicating with the server yet.
2. **Sync with Server** – You synchronize the updated license state with the LicenseSpring cloud server. At this stage, the actual consumption is registered on the server and reflected on the platform.

## UpdateConsumption

This method updates the `LocalConsumptions` value in the local license file, if the value alligns with license's specifications.



```go
	ld, err = lh.UpdateConsumption(1)

	t := ld.TotalConsumptions
	l := ld.LocalConsumptions
	fmt.Printf("Total Consumptions: %d\n  Local Consumptions: %d\n", t, l)
```

## SyncConsumption

This method synchronizes the current `LocalConsumptions` value with the LicenseSpring cloud server.
&#x20;If the sync is successful and no errors are returned, the local license file is updated as follows:

- `TotalConsumptions` is incremented (or decremented) based on the local value.
- `LocalConsumptions` is reset to zero.

This update will also be visible on the LicenseSpring platform dashboard.

`SyncConsumption` also can request the server to allow overages. The second argument is whether to ask for overages and the third is the number of overages requested, if any.

If overages requested, the change will be reflected both in local license file and platform.

```go
	ld, err = lh.SyncConsumption(ctx, false, 0)

	t := ld.TotalConsumptions
	l := ld.LocalConsumptions
	fmt.Printf("Total Consumptions: %d\n  Local Consumptions: %d\n", t, l)
```


[title] Go License Client
[path] SDKs/Go SDK/v1 (legacy)/

:::hint{type="info"}
LicenseSpring’s new [**Go SDK V2**](docId\:rDJT5fZ-ZkOsGHD5Jso9c)  is now available! This version is a complete rewrite with breaking changes and will receive all future updates and support.

The legacy Go SDK (v1) is deprecated and maintained for backward compatibility only. New users should use v2.
:::

:::BlockQuote
**&#xA;Note:** Read [**Common**](docId\:u_qOx_n0BARrlS2ujjS1_) before this.
:::

### Importing the License Client

```go

import (
	"gitlab.com/l3178/sdk-go/license_client"
	"gitlab.com/l3178/sdk-go/core/auth"
	core_request "gitlab.com/l3178/sdk-go/core/models/request"
)
```

### Create LicenseClient

The following function uses the default `CryptoProvider` and `DataLocation` to encrypt, store, and decrypt the license file. You can implement your custom `CryptoProvider` and `DataLocation` the interface structure.

```go
config := license_client.NewLicenseClientConfiguration("apiKey", "sharedKey", "productCode")
client := license_client.NewLicenseClient(config)
```

### Create Custom LicenseClient

Implement the `CryptoProvider` and `DataLocation` interfaces to create custom implementations for these components, and use them to configure the license client.

```go
// implement the interface:
//type CryptoProvider interface {
//	Encrypt(core_models.LicenseFile, string) (interface{}, error)
//	Decrypt(interface{}, string) (interface{}, error)
//}
type CustomCryptoProvider struct{}
func (d CustomCryptoProvider) Encrypt(license_file core_models.LicenseFile, password string) (interface{}, error) {
// your custom implementation
}
func (d CustomCryptoProvider) Decrypt(data interface{}, password string) (interface{}, error) {
// your custom implementation
}

// implement the interface:
//type DataLocation interface {
//	DataDirectory() (string, error)
//	LicenseFileName(string) string
//}
type CustomDataLocation struct{}
func (d CustomDataLocation) DataDirectory() (string, error) {
// your custom implementation
}
func (d CustomDataLocation) LicenseFileName(productCode string) string {
// your custom implementation
}

config := license_client.NewLicenseClientConfigurationCustom(CustomCryptoProvider, CustomDataLocation, "apiKey", "sharedKey", "productCode")
client := license_client.NewLicenseClient(config)

```

### Activate Key-Based License

After activating the license, this function saves the license file in the location specified by the `DataLocation` object. The file is securely encrypted using the implementation provided by the `CryptoProvider`.

```go
resp := client.ActivateLicense(license_client.ActivationRequest{
	LicenseRequest: core_request.LicenseRequest{
		Auth: auth.FromKey("licenseKey"),
	},
	Hostname:       "hostname",
	AppVersion:     "1.1.1",
	...
})
```

### Activate User-Based License

After activating the license, this function saves the license file in the location specified by the `DataLocation` object. The file is securely encrypted using the implementation provided by the `CryptoProvider`.

```go
resp := client.ActivateLicense(license_client.ActivationRequest{
	LicenseRequest: core_request.LicenseRequest{
		Auth: auth.FromUsername("username", "password"),
	},
	Hostname:       "hostname",
	AppVersion:     "1.1.1",
	...
})
```

### Deactivate Key-Based License

```go
err := client.DeactivateLicense(license_client.LicenseRequest{
	Auth: auth.FromKey("licenseKey"),
})
```

### Deactivate User-Based License

```go
err := client.DeactivateLicense(license_client.LicenseRequest{
	Auth: auth.FromUsername("username", "password"),
})
```

### Check Key-Based License

```go
resp := client.CheckLicense(license_client.ActivationRequest{
	LicenseRequest: core_request.LicenseRequest{
		Auth: auth.FromKey("licenseKey"),
	},
	...
})
```

### Check User-Based License

```go
resp := client.CheckLicense(license_client.ActivationRequest{
	LicenseRequest: core_request.LicenseRequest{
		Auth: auth.FromUsername("username", "password"),
	},
	...
})
```

### Activate Offline License

After activating the license, this function saves the license file in the location specified by the `DataLocation` object. The file is securely encrypted using the implementation provided by the `CryptoProvider`.

```go
// Generate offline license request data
resp := client.GenerateOfflineLicenseRequest(license_client.ActivationRequest{
	LicenseRequest: core_request.LicenseRequest{
		Auth:       auth.FromKey("licenseKey"),
	},
}, license_client.OfflineActivationRequest)

// Write to request file if you want to activate license manually
encoded, err := resp.Value.Encode()
ioutil.WriteFile("activate_offline.req", []byte(encoded), os.ModePerm)

// Activate offline license using API
client.ActivateOffline(offlineLicenseRequest)
```

### Deactivate Offline License

```go
// Generate offline license request data
resp := client.GenerateOfflineLicenseRequest(license_client.ActivationRequest{
	LicenseRequest: core_request.LicenseRequest{
		Auth:       auth.FromKey("licenseKey"),
	},
}, license_client.OfflineDeactivationRequest)

// Write to request file if you want to deactivate license manually
encoded, err := resp.Value.Encode()
ioutil.WriteFile("deactivate_offline.req", []byte(encoded), os.ModePerm)

// Deactivate offline license using API
client.DeactivateOffline(offlineLicenseRequest)
```

### Local License Check

This function reads the license file from local memory, validates it by performing checks such as expiration and hardware ID matching, and returns the license object along with the results of these checks.

```go
clientConfig := license_client.NewLicenseClientConfiguration(
		config.ApiKey,
		config.SharedKey,
		productCode,
	)
clientConfig.Verbose = config.Verbose
clientConfig.VerifySignature = config.VerifySignature

client := license_client.NewLicenseClient(clientConfig)


resp := client.ActivateLicense(context.Background(), license_client.ActivationRequest{
	LicenseRequest: core_request.LicenseRequest{
		Product: productCode,
		Auth: auth.FromKey(productAuth.LicenseKey),
	},
})

resp2 := client.LocalLicenseCheck(context.Background(), 
license_client.LocalLicenseCheckRequest{Product: productCode})
```

Local license check returns an object of the following type:

:::CodeblockTabs
Go

```go
type LocalCheckResponse struct {
	LicenseResponse

	LicenseActive  bool `json:"license_active"`
	LicenseEnabled bool `json:"license_enabled"`
	IsExpired      bool `json:"is_expired"`

	DeviceLicensed bool `json:"is_device_licensed"`
	IsClockTampered  bool `json:"is_clock_tampered"`
	ProductMismatch bool `json:"product_mismatch"`
	FloatingExpired bool `json:"floating_expired"`
}
```
:::

### Add Consumption

```go

# Add 1 consumption
resp := client.AddConsumption(license_client.ConsumptionRequest{
	LicenseRequest: core_request.LicenseRequest{
		Auth:       auth.FromKey("licenseKey"),
	},
	Consumptions:   1,
})

# Add 1 consumption, allow overages and define max overages
resp := client.AddConsumption(license_client.ConsumptionRequest{
	LicenseRequest: core_request.LicenseRequest{
		Auth: auth.FromKey("licenseKey"),
	},
	Consumptions:  1,
	MaxOverages:   5,
	AllowOverages: true,
})
```

### Add Feature Consumption

```go

resp := client.AddFeatureConsumption(license_client.FeatureConsumptionRequest{
	LicenseRequest: license_client.LicenseRequest{
		Auth: core_request.Auth{}.FromKey("licenseKey"),
	},
	Feature:        "featureCode",
	Consumptions:   1,
})
```

### Trial Key

```go
resp := client.TrialKey(license_client.TrialLicenseRequest{
	LicenseRequest: core_request.LicenseRequest{
		Auth: auth.FromKey("licenseKey"),
	},
	Email:          "",
	LicensePolicy:  "",
	FirstName:      "",
	LastName:       "",
	Phone:          "",
	Address:        "",
	PostCode:       "",
	State:          "",
	Country:        "",
	City:           "",
	Reference:      "",
})
```

### Product Details

```go

// takes product code from configuration
resp := client.ProductDetails()
```

### Track Device Variables

```go

err := client.TrackDeviceVariables(license_client.DeviceVariablesRequest{
	LicenseRequest: core_request.LicenseRequest{
		Auth: auth.FromKey("licenseKey"),
	},
	Variables: map[string]string{
		"key": "var",
	},
})
```

### Get Device Variables

```go
resp := client.GetDeviceVariables(license_client.LicenseRequest{
	Auth: auth.FromKey("licenseKey"),
})
```

### Floating Borrow

```go
resp := client.FloatingBorrow(license_client.FloatingBorrowRequest{
	LicenseRequest: license_client.LicenseRequest{
		Auth: auth.FromKey("licenseKey"),
	},
	BorrowedUntil:  time.Now().UTC().Add(time.Hour * 24 * 5),
})
```

### Floating Release

```go
client.FloatingRelease(license_client.LicenseRequest{
	Auth: auth.FromKey("licenseKey"),
})
```

### Change Password

```go
client.ChangePassword(license_client.ChangePasswordRequest{
	PasswordAuth: core_request.PasswordAuth{
		Username: "username",
		Password: "password",
	},
	NewPassword:  "abcd",
})
```

### Versions

```go
resp := client.Versions(license_client.LicenseRequest{
	Auth: auth.FromKey("licenseKey"),
})
```

### Installation File

```go

resp := client.InstallationFile(license_client.LicenseRequest{
	Auth: auth.FromKey("licenseKey"),
})
```

### Customer License Users

```go
resp := client.CustomerLicenseUsers(license_client.CustomerLicenseUsersRequest{
	Customer: "customer",
})
```

### SSO URL

```go
resp := client.SSOUrl(license_client.SSOUrlRequest{
	CustomerAccountCode: "code",
})
```

### Air-Gap Initialization

```go
airgapClient := license_client.NewAirgapClient(config, "publicKey")
activationCode, err := airgapClient.AirgapInitialization("licenseKey", "signingKey")
return activationCode, cfg.HardwareId
```

### Air-Gap Activation

```go
airgapClient := license_client.NewAirgapClient(config, "publicKey")
license, err := airgapClient.AirgapActivation("licensePolicy", "confirmationCode", 1234)
```


[title] Set API and Shared keys
[path] Floating Server/Floating Server V1/API Reference/config/

{
  "id": "gMoarRftgVrJMSBm7xTF1",
  "data": {
    "url": "http://localhost:8080/api/v4/setKeys",
    "name": "Set API and Shared keys",
    "method": "GET",
    "request": {
      "pathParameters": [],
      "queryParameters": [
        {
          "kind": "optional",
          "name": "apiKey",
          "type": "string"
        },
        {
          "kind": "optional",
          "name": "sharedKey",
          "type": "string"
        }
      ],
      "headerParameters": [],
      "bodyDataParameters": [],
      "formDataParameters": []
    },
    "responses": [
      {
        "statusCode": "200",
        "description": "",
        "jsonExample": ""
      }
    ],
    "contentType": "application/json",
    "description": "Set API and Shared keys",
    "examples": {
      "languages": [
        {
          "id": "2pIobxaoBEbEfm0rCuy3D",
          "language": "curl",
          "label": "cURL",
          "code": "curl --location 'http://localhost:8080/api/v4/setKeys' \\\n--header 'Accept: application/json' \\\n--header 'Content-Type: application/json'"
        },
        {
          "id": "Zipv5quIWwTn2ff-JC-q1",
          "language": "javascript",
          "label": "javascript",
          "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Content-Type\", \"application/json\");\n\nvar requestOptions = {\n   method: 'GET',\n   headers: myHeaders,\n   redirect: 'follow'\n};\n\nfetch(\"http://localhost:8080/api/v4/setKeys\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));"
        },
        {
          "id": "jGiceDcCKD5FRCtFJBHi9",
          "language": "ruby",
          "label": "Ruby",
          "code": "require \"uri\"\nrequire \"json\"\nrequire \"net/http\"\n\nurl = URI(\"http://localhost:8080/api/v4/setKeys\")\n\nhttp = Net::HTTP.new(url.host, url.port);\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Accept\"] = \"application/json\"\nrequest[\"Content-Type\"] = \"application/json\"\n\nresponse = http.request(request)\nputs response.read_body\n"
        },
        {
          "id": "InQmzKqHUgU5XLo35WgGJ",
          "language": "python",
          "label": "Python",
          "code": "import requests\nimport json\n\nurl = \"http://localhost:8080/api/v4/setKeys\"\n\npayload = {}\nheaders = {\n   'Accept': 'application/json',\n   'Content-Type': 'application/json'\n}\n\nresponse = requests.request(\"GET\", url, headers=headers, data=payload)\n\nprint(response.text)\n"
        }
      ],
      "selectedLanguageId": "2pIobxaoBEbEfm0rCuy3D"
    },
    "results": {
      "languages": [
        {
          "id": "aMGYv9kqwqKQ89ufR_pKn",
          "language": "200",
          "code": ""
        }
      ],
      "selectedLanguageId": "aMGYv9kqwqKQ89ufR_pKn"
    }
  },
  "type": "api-oas-v2",
  "children": [
    {
      "id": "wapXyyiYx67uREfyyboRH",
      "type": "paragraph",
      "children": [
        {
          "text": "Set API and Shared keys"
        }
      ]
    }
  ]
}
[title] Bundle Manager
[path] SDKs/node.js SDK/

## BundleManager

Provides a high-level interface for managing bundle licenses, including local bundle licenses. The BundleManager is required to work with local bundle license files. This class can share the same license file with the LicenseManager, as both classes are designed to not overwrite each other's data.

Typescript definitions are provided for the arguments and return types of the class methods.

To import the BundleManager class use:

```javascript
const { BundleManager } = require('@licensespring/node-sdk');
```

To create an instance:

```javascript
const bundleManager = new BundleManager({
  apiKey: '12345678-4bfe-4e3a-8737-757004d6294c',
  sharedKey: 'eYuHrlajvIVTiSFIXpxpKhw78f4Ewy-00-12345678',
  appName: 'js-sdk-test-1',
  appVersion: '0.0.1',
  productCode: 'bkp',
  /** NOTE: the following properties are set to their default values by the SDK and can be overriden manually: */
  // apiPath: 'http://api.dev.licensespring.com/api/v4',
  // publicKey: '...',
});
```

The constructor takes the a single argument of the following type:

```typescript
{
  /** your Licensespring API key */
  apiKey: string,
  /** your Licensespring API Shared key **/
  sharedKey: string,
  /** custom name for your application */
  appName: string,
  /** custom version string for your application */
  appVersion: string,
  /** your product short code */
  productCode: string,
  /** your Air Gap Activation key (optional) */
  airGapKey?: string,
  /** override for License API url (default is https://api.licensespring.com/api/v4/) **/
  apiPath?: string,
  /** override for License API public key (default is pub key for api.licensespring.com) **/
  publicKey?: string,
  /** override for License File filename (default is "License") */
  filename?: string,
  /** override for License File path (default is current directory) */
  filePath?: string,
  /** override for License File encryption key */
  fileKey?: string,
  /** override for license grace period duration in hours (default is 24) */
  gracePeriod?: number,
  /** override for License File guard file (default is false) */
  isGuardFileEnabled?: boolean,
  /** override for Hardware ID calculation method (default is 0, for more info see "Hardware ID" section) */
  hardwareIDMethod?: number,
  /** a custom provided Hardware ID (overrides HWID calculation) */
  hardwareID?: string,
}
```

## Methods

Methods listed here which take a license payload are the similar to corresponding methods in the License API class, except that `product` and `hardware_id` do not have to be specified in the payload as they are provided by the Bundle Manager object.

### Check Bundle License

See: [**Check Bundle**](docId\:odudSbU1BNxycgT4zx8FW) &#x20;

```typescript
checkBundle(
  payload: CheckBundlePayload, 
  includeExpiredFeatures: boolean = false
): Promise<CheckLicenseResponse[]>

type CheckLicensePayload = ({
  username: string;
} | {
  license_key: string;
}) & {
  env: string | undefined;
  license_id: number | undefined;
  sdk_ver: string | undefined;
  app_ver: string | undefined;
  hostname: string | undefined;
  os_hostname: string | undefined;
  ip_local: string | undefined;
  mac_address: string | undefined;
  ip: string | undefined;
  os_ver: string | undefined;
  channel: string | undefined;
};

type CheckLicenseResponse = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  allow_offline_activation: boolean,
  can_borrow: boolean,
  custom_fields: CustomField[],
  customer: CustomerResponse,
  enable_maintenance_period: boolean,
  floating_timeout: number,
  floating_users?: number,
  grace_period: number | null,
  is_air_gapped: boolean,
  is_floating: boolean,
  is_floating_cloud: boolean,
  is_hardware_key_auth: boolean,
  license_key: string | undefined,
  license_template_id?: number,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users?: number,
  max_overages: number,
  max_transfers?: number,
  metadata: JSONObjectRequired,
  metadata_string?: string,
  order_store_id?: string,
  prevent_vm: boolean,
  company: {
    id: number,
  },
  product_details?: ProductDetailsResponse,
  product_features: FeatureResponse[],
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null,
  is_trial: boolean,
  trial_days?: number,
  user?: LicenseUserResponse,
  license_type: LicenseTypes,
  allow_negative_consumptions?: boolean,
  allow_unlimited_consumptions?: boolean,
  consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
  max_consumptions?: number,
  reset_consumption?: boolean,
  total_consumptions?: number,
  borrowed_until: string | null,
  floating_in_use_devices?: number,
  is_borrowed: boolean,
  is_expired: boolean,
  license_active: boolean,
  license_enabled: boolean,
  license_signature: string,
};
```

### Activate Bundle License Online

See: [**Activate Bundle (Online Method)**](docId\:sj4ujBbDqwMf3QJDVNHdh)&#x20;

```typescript
activateBundle(payload: ActivateBundlePayload): Promise<ActivateLicenseResponse[]>

type ActivateBundlePayload = ({ 
  license_key: string; 
} | {
  username: string;
  password: string;
} | {
  code: string;
  customer_account_code: string;
} | {
  id_token: string;
  customer_account_code: string;
}) & {
  variables: { [key: string]: string | number | boolean } | undefined;
};

type ActivateLicenseResponse = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  allow_offline_activation: boolean,
  can_borrow: boolean,
  custom_fields: CustomField[],
  customer: CustomerResponse,
  enable_maintenance_period: boolean,
  floating_timeout: number,
  floating_users?: number,
  grace_period: number | null,
  is_air_gapped: boolean,
  is_floating: boolean,
  is_floating_cloud: boolean,
  is_hardware_key_auth: boolean,
  license_key: string | undefined,
  license_template_id?: number,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users?: number,
  max_overages: number,
  max_transfers?: number,
  metadata: JSONObjectRequired,
  metadata_string?: string,
  order_store_id?: string,
  prevent_vm: boolean,
  company: {
    id: number,
  },
  product_details?: ProductDetailsResponse,
  product_features: FeatureResponse[],
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null,
  is_trial: boolean,
  trial_days?: number,
  user?: LicenseUserResponse,
  license_type: LicenseTypes,
  allow_negative_consumptions?: boolean,
  allow_unlimited_consumptions?: boolean,
  consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
  max_consumptions?: number,
  reset_consumption?: boolean,
  total_consumptions?: number,
  request: string,
  active: boolean,
  device_id: number,
  validity_period: string | null,
  is_expired: boolean,
  hardware_id: string,
  username?: string,
  max_license_users?: number,
  is_floating_cloud: boolean,
  floating_in_use?: boolean,
  license_signature: string,
  variables?: ({
    value: string;
    device_id: number;
    variable: string;
    created_at: string | null;
  })[];
};
```

### Deactivate License Online

See: [**Deactivate Bundle (Online Method)**](docId\:nzu6SRyNQLlEd2_-HhvhR)&#x20;

```typescript
deactivateBundle(payload: ({  
  username: string;
} | {
  license_key: string;
}): Promise<boolean>
```

### Activate Bundle License Offline

See: [**Activate Bundle (Offline Method)**](docId:0AWEA7jLUGzT14Z9_QSqi)&#x20;

```typescript
activateOffline(payload: string): Promise<ActivateOfflineResponse>

type ActivateOfflineResponse = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  allow_offline_activation: boolean,
  can_borrow: boolean,
  custom_fields: CustomField[],
  customer: CustomerResponse,
  enable_maintenance_period: boolean,
  floating_timeout: number,
  floating_users?: number,
  grace_period: number | null,
  is_air_gapped: boolean,
  is_floating: boolean,
  is_floating_cloud: boolean,
  is_hardware_key_auth: boolean,
  license_key: string | undefined,
  license_template_id?: number,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users?: number,
  max_overages: number,
  max_transfers?: number,
  metadata: JSONObjectRequired,
  metadata_string?: string,
  order_store_id?: string,
  prevent_vm: boolean,
  company: {
    id: number,
  },
  product_details?: ProductDetailsResponse,
  product_features: FeatureResponse[],
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null,
  is_trial: boolean,
  trial_days?: number,
  user?: LicenseUserResponse,
  license_type: LicenseTypes,
  allow_negative_consumptions?: boolean,
  allow_unlimited_consumptions?: boolean,
  consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
  max_consumptions?: number,
  reset_consumption?: boolean,
  total_consumptions?: number,
  request: string,
  active: boolean,
  device_id: number,
  validity_period: string | null,
  is_expired: boolean,
  hardware_id: string,
  username?: string,
  max_license_users?: number,
  is_floating_cloud: boolean,
  floating_in_use?: boolean,
  license_signature: string,
  variables?: ({
    value: string;
    device_id: number;
    variable: string;
    created_at: string | null;
  })[];
  date: string,
  offline_signature: string,
  license_signature_v2: string,
};
```

### Deactivate Bundle License Offline

Performs an offline deactivation

```typescript
deactivateOffline(): Promise<boolean>
```

### Change Password

See: [**Change Password**](docId\:B4ixyzvAh4TAltTuuajyi)&#x20;

```typescript
changePassword(payload: {
    username: string;
    password: string;
    new_password: string;
}): Promise<boolean>
```

### Get Product Versions

See: [**Get Product Versions**](docId\:mBq0eK4XlT_jX8SLdyHY9)&#x20;

```typescript
getVersions(payload: GetVersionsPayload): Promise<VersionsResponse>

type GetVersionsPayload = ({
    license_key: string;
} | {
    username: string;
}) & {
    sdk_ver: string | undefined;
    env: string | undefined;
    channel: string | undefined;
};

type VersionsResponse = ({
  version: string | undefined;
  release_date: string | null;
})[];
```

### Get Product Installation File

See: [**Get Installation File**](docId\:LxPe6kV-OLj7HLL-GrL1q)&#x20;

```typescript
getInstallationFile(payload: GetInstallationFilePayload): Promise<InstallationFileResponse>

type GetInstallationFilePayload = ({
    license_key: string;
} | {
    username: string;
}) & {
    sdk_ver: string | undefined;
    env: string | undefined;
    channel: string | undefined;
    version: string | undefined;
};

type InstallationFileResponse = {
  id: number;
  version: string | undefined;
  installation_file: string | undefined;
  release_date: string | null;
  hash_md5: string | undefined;
  environment: string;
  eula_link: string | undefined;
  release_notes_link: string | undefined;
  size: string | undefined;
  requires_version: string | undefined;
  channel: string | undefined;
  company: {
    id: number;
  };
};
```

### Get Single Sign-On URL

See: [**Single Sign-On URL**](docId\:QbJwnphsDcS0L25UW6PTq)&#x20;

```typescript
getSSOUrl(payload: {
    response_type: 'token' | 'code' | undefined;
    product: string;
    customer_account_code: string;
}): Promise<SSOUrlResponse>

type SSOUrlResponse = {
  url: string;
  openid_configuration: {
    [key: string]: string | number | boolean;
  };
};
```

### License Utility Methods

The following methods on the BundleManager class take a single argument which is the license object returned from a license activation, a license check or parsed from the license file.

Checks if License is enabled, active and not expired:

```typescript
isValid(license: {
    license_active: boolean,
    license_enabled: boolean,
    validity_period: DateISO8601UTC | null,
  }): boolean
```

Returns days remaining in maintenance period:

```typescript
maintenanceDaysRemaining(license: {
    enable_maintenance_period: boolean
    maintenance_period: string | null,
  }): number
```

Returns days remaining in license validity period:

```typescript
daysRemaining(license: {
    grace_period: number,
    validity_period: DateISO8601UTC | null,
  }): number
```

### License File

See [**License File**](https://www.npmjs.com/package/@licensespring/node-sdk#license-file)

```typescript
/** Reads and parses the local license file and returns its data as a License object */
loadBundle(): License

/** Verifies the local bundle license file's integrity */
isLicenseFileCorrupted(): boolean

/** Deletes the local bundle license file and guard file */
clearLocalStorage(): void
```

##


[title] Offline License
[path] SDKs/Go SDK/v2/Samples/

The LicenseSpring SDK supports full offline license activation, refresh, and deactivation. This is useful in the environments where no direct internet access is available on the client machine. This guide walks you through the entire offline flow using the SDK.

## Overview

Offline licensing is a multi-step process involving manual steps with the LicenseSpring portal:

1. **Generate an Offline Activation Request**
2. **Upload the Request to the Portal and Download the Activation File**
3. **Use the Activation File to Activate the License Locally**
4. *(Optional)* **Apply Updates via a Refresh File**
5. **Deactivate the License and Upload the Deactivation Request File**

Each of these steps has a corresponding function in the SDK.

## 1. Generate Offline Activation Request

This function creates an activation request file and stores it in a specified or default path (Desktop). You can upload this request on the LicenseSpring portal to get a license activation file.

```go
	// Provide a path where the request file should be stored.
	// If an empty string is given, the file will be saved to the default desktop path.
	offlineActivationData, path, err := lh.CreateOfflineActivationFile("")
	if err != nil {
		return err
	}

	fmt.Printf("Offline Activation Request Data: %s\n Stored in path: %s\n", offlineActivationData, path)
```

By uploading this request file to the LicenseSpring's offline portal, you can activate the license and receive a license activation file.

## 2. Activate License Using Activation File

After receiving the activation file from the LicenseSpring portal, use this method to activate the license locally. The file is verified (signature, hardware ID, etc.) before updating the local license state.

```go
	// Provide the path to the license activation file obtained from the portal.
	// The SDK verifies the file (signature, hardware ID, etc.) and stores the license locally.
	ld, err := lh.ActivateLicenseOffline(path)
	if err != nil {
		return err
	}
```

The LicenseSpring SDK supports full offline license activation, refresh, and deactivation. This is useful in air-gapped environments where no direct internet access is available on the client machine. This guide walks you through the entire offline flow using the SDK.

## 2. Update License Using Refresh File

If the license is updated on the portal (e.g., extended expiration, additional features), you can download a refresh file and update your local license using this function. The second argument specifies whether to reset local consumption counts. If set to false, the number of local consumptions remain unchanged, otherwise, this value will be set to zero.

```go
	ld, err := lh.OfflineUpdate(path, true)
	if err != nil {
		return err
	}
```

## 2.  Generate Offline DeActivation Request

This function creates a deactivation request file that includes local license state (e.g., updated consumptions). Upload this file to the LicenseSpring portal to complete the deactivation. After calling this function, the license should be marked as inactive locally. License Offline Deactivation updates the LicenseSpring server with the lastest state of the license before being deactivated.

```go
	ld, deactivationReq, path, err := lh.DeactivateOffline("")
	if err != nil {
		return err
	}
```

## Notes

- These offline flows are meant for environments where no internet access is available.
- Offline deactivation is currently the only way to sync local changes (such as consumption updates) back to the cloud in offline mode.


[title] node.js SDK
[path] SDKs/

The @licensespring/node-sdk package is a node.js implementation of Licensespring SDK. It provides an interface for working with our API and Licenses

[title] Storage
[path] SDKs/Go SDK/v2/License Handler/

## Storage

The `Storage` interface is designed to be a flexible and extensible abstraction for any storage backend used in the SDK. It provides a minimal contract that allows upper layers (like the license handler) to persist license data securely, regardless of the actual implementation (file system, database, remote service, etc.).

### Storage Interface

```go
type Storage interface {
	SetCryptoProvider(cryptoProvider crypto_provider.CryptoProvider)
	GetCryptoProvider() crypto_provider.CryptoProvider
}
```

These setter and getter functions ensure that every `Storage` implementation uses a `CryptoProvider` to handle encryption and decryption of sensitive license data. This guarantees that all stored data—regardless of format or location—is encrypted with a consistent mechanism.

## File Storage

The SDK includes a built-in implementation of Storage called FileStorage, which persists encrypted data locally to disk. This interface extends Storage and defines all methods required to manage license files, guard files, and any encrypted metadata.

### FileStorage Interface

```go
type FileStorage interface {
	Storage
	DataDirectory() (string, error)
	LicenseFileName(string) string
	SaveLicense(data interface{}) error
	LoadLicense(fileName string) (license_file.LicenseFile, error)
	ClearLocalLicenseData(productCode string) error
	OfflineGuardPath() (string, error)
	StoreEncryptedData(path string, data interface{}) error
	LoadEncryptedData(path string, out interface{}) error
	LoadGuardFile(password string) (types.OfflineActivationGuard, error)
	SaveGuardFile(guard interface{}) error
	RemoveFile(file_path string) error
}
```

This interface provides all the required capabilities for securely storing and retrieving license and guard files using encryption. It can be used as-is or replaced with a custom storage implementation.

## Crypto Provider

The CryptoProvider interface is responsible for encryption and decryption of sensitive data before it is saved or after it is loaded. It is designed to be pluggable, allowing you to implement your own encryption scheme if needed.

### CryptoProvider Interface

```go
type CryptoProvider interface {
	Encrypt(license_file interface{}) (interface{}, error)
	Decrypt(data interface{}) (interface{}, error)
	SetKey(password string)
	GetKey() (string, error)
}
```

Any implementation of this interface must be able to securely encrypt and decrypt data using a key that can be set or retrieved. The SDK comes with a `DefaultCryptoProvider` implementation that uses AES encryption.

## Default Implementations

Both FileStorage and CryptoProvider come with default implementations:

- DefaultFileStorage – uses local disk paths to save and retrieve encrypted license data.
- DefaultCryptoProvider – performs AES encryption and decryption using a key you provide.

You can use them directly when creating a LicenseHandler, or omit them entirely and let the SDK initialize the defaults automatically.

Example usage:

```go
cp := crypto_provider.DefaultCryptoProvider{}
cp.SetKey("my-encryption-key")

storage := data_handler.DefaultFileStorage{}
storage.SetCryptoProvider(&cp)

cfg := license_handler.LicenseHandlerConfig{
	ApiKey:      "your-api-key",
	SharedKey:   "your-shared-key",
	ProductCode: "my-product",
	AuthData:    auth.FromKey("LICENSE_KEY"),
	Storage:     storage,
}
```

This setup allows you to override either the storage mechanism or the crypto logic without touching the SDK’s licensing logic.

[title] Go Changelog
[path] SDKs/Go SDK/v1 (legacy)/

:::hint{type="info"}
LicenseSpring’s new [**Go SDK V2**](docId\:rDJT5fZ-ZkOsGHD5Jso9c)  is now available! This version is a complete rewrite with breaking changes and will receive all future updates and support.

The legacy Go SDK (v1) is deprecated and maintained for backward compatibility only. New users should use v2.
:::

## Release Notes

### v1.0.16. - 15.11.2024

- License file encrypted and stored in local memory
- Local License Check implemented
- Default Crypto Provider and Data Location added

### v1.0.15. - 18.10.2024.

- Offline license activation and deactivation corrected
- Usecase samples added

### v1.0.14. - 02.10.2023.

- Custom unmarshalling of a nillable time in InstallationFileResponse

### v1.0.13. - 20.6.2023.

- General improvements
- More Management API tests

### v1.0.12 - 16.6.2023.

- General fixes and improvements
- License client tests

### v1.0.11 - 6.6.2023.

- Management client tests

### v1.0.10 - 6.6.2023.

- Management client updates

### v1.0.9 - 8.5.2023.

- API response struct change

### v1.0.8 - 3.2.2023.

- Airgap implementation

### v1.0.7 - 28.11.2022.

- Serialization/deserialization fixes

### v1.0.6 - 15.11.2022.

- Encoding/decoding improvements

### v1.0.5 - 15.11.2022.

- Encoding bug fix

### v1.0.4 - 21.10.2022.

- Implemented new endpoints

### v1.0.3 - 3.5.2022.

- Initial SDK


[title] License
[path] SDKs/Python SDK/

::File[]{src="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/yRYy-zaLd3QWOFOFvZ1ph_.LICENSE" signedSrc="https://archbee-doc-uploads.s3.us-east-1.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/yRYy-zaLd3QWOFOFvZ1ph_.LICENSE?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAYQNQCIXNIQWBC56C%2F20250203%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250203T105139Z&X-Amz-Expires=86400&X-Amz-Signature=572002b5d4dc4820498a02bfdb47dd2ff4248e049e8dbf1ed5b42790bc8c1ec0&X-Amz-SignedHeaders=host&x-id=GetObject" label="LICENSE" isUploading="false"}

### Dependency licenses

| Name               | Version   | License                                             | URL                                                                                                                      |
| ------------------ | --------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| certifi            | 2025.1.31 | Mozilla Public License 2.0 (MPL 2.0)                | [**https://github.com/certifi/python-certifi**](https://github.com/certifi/python-certifi)                               |
| charset-normalizer | 3.4.1     | MIT License                                         | [**https://github.com/Ousret/charset\_normalizer**](https://github.com/Ousret/charset_normalizer)                        |
| idna               | 3.10      | BSD License                                         | [**https://github.com/kjd/idna**](https://github.com/kjd/idna)                                                           |
| pycryptodome       | 3.21.0    | Apache Software License; BSD License; Public Domain | [**https://www.pycryptodome.org**](https://www.pycryptodome.org)                                                         |
| requests           | 2.32.3    | Apache Software License                             | [**https://requests.readthedocs.io**](https://requests.readthedocs.io)                                                   |
| urllib3            | 2.3.0     | MIT License                                         | [**https://github.com/urllib3/urllib3/blob/main/CHANGES.rst**](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) |
| winregistry        | 2.1.0     | MIT License                                         | [**https://github.com/shpaker/winregistry**](https://github.com/shpaker/winregistry)                                     |


[title] nodeJS SDK Changelog
[path] SDKs/node.js SDK/

### v1.4.7, 18.02.2026.

- Added activation\_date to license files
- Added SSO support for floating borrow
- Added installation\_file object to license activation response
- Fixed a consumption-syncing bug in LicenseManager.checkLicense

### v1.4.5, 19.12.2025.

- Added automatic consumption sync when calling LicenseManager.checkLicense
- Added optional redirect\_uri for SSO authentication
- Fixed a bug with the License.deactivateOffline method

:::Changelog{title="v1.4.0, 28.11.2025."}
::ChangelogItem{type="fixed" description="Fixed a bug with device variables not being saved"}

::ChangelogItem{type="fixed" description="Fixed a bug where a hwID check was being overriden for a copied license file"}

::ChangelogItem{type="fixed" description="Fixed a bug where feature local check was incorrectly comparing consumption values"}

::ChangelogItem{type="fixed" description="Fixed a bug where feature release was calling the wrong endpoint"}

::ChangelogItem{type="fixed" description="Fixed a license file parsing bug"}
:::

:::Changelog{title="v1.3.11, 02.10.2025."}
::ChangelogItem{type="added" description="Implemented Floating Server v2 API"}

::ChangelogItem{type="fixed" description="Fixed a bug with parsing airgap activation responses"}
:::

:::Changelog{title="v1.2.0, 10.07.2025."}
::ChangelogItem{type="added" description="Implemented support for bundle actions and bundle license files"}

::ChangelogItem{type="added" description="Added support for hardware ID override to LicenseAPI and LicenseManager classes"}

::ChangelogItem{type="fixed" description="Fixed license status not being saved when license check fails"}
:::

:::Changelog{title="v1.1.18, 10.06.2025."}
::ChangelogItem{type="fixed" description="Fixed `License.isFloatingExpired` check"}
:::

:::Changelog{title="v1.1.17, 20.05.2025."}
::ChangelogItem{type="added" description="Implemented support for OAuth"}

::ChangelogItem{type="added" description="Implemented call and error logging"}

::ChangelogItem{type="fixed" description="Fixed license refresh file parsing for company code"}
:::

:::Changelog{title="v1.1.14, 07.04.2025."}
::ChangelogItem{type="added" description="Implemented offline activation file functionality"}

::ChangelogItem{type="fixed" description="Fixed a bug for http proxies in the internal proxy library"}
:::

:::Changelog{title="v1.0.10, 20.03.2025."}
::ChangelogItem{type="fixed" description="Fixed a proxy bug in the internal proxy library"}
:::

:::Changelog{title="v1.0.9, 26.02.2025."}
::ChangelogItem{type="added" description="Support for proxy configuration"}
:::


[title] SDK Initialization
[path] SDKs/Android SDK/

The SDK behaves as a singleton - this means you initialize the SDK only once and use it many times. As soon as you initialize the SDK, it will contact the LicenseSpring server to check if there is an existing license for the current computer / product combination.

If there is a current license available, it will be immediately accessible as a License object.

At the **minimum** there are **three parameters** you will need to initialize the SDK:

- `apiKey`, your company API key
- `productCode`, a two-letter string identifying product (particular application)
- `sharedKey`, company-specific encryption key, used when signing requests

All of these values are available to you in the LicenseSpring web platform under "SDK integration" section.

`LicenseManager` takes two arguments for initialization, `LicenseSpringConfiguration` and application context. Application context is used for saving license files to internal app storage.

```java
LicenseSpringConfiguration configuration = LicenseSpringConfiguration.builder()
                        .apiKey("api_key")
                        .productCode("product_code")
                        .sharedKey("shared-key")
                        .appName("My application")
                        .appVersion("1.0.0")
                        .build();

        LicenseManager manager = LicenseManager.getInstance();

        manager.initialize(configuration, getApplicationContext());
```

During initialization the `LicenseManager` will try to read the license information from specified license file and check the license information with the license server. In case it succeeds `LicenseManager.getCurrent()` will return `License` object with detailed license information specified.

The SDK has a hardware key generator based on the Secure Android ID. If the Secure Android ID is null, UUID will be used as a hardware key.

[title] 
[path] SDKs/


[title] Build your Program
[path] SDKs/Go SDK/v2/

# **Building Your Program with Go and Garble**

When building your application using our SDK, we recommend two primary methods:

- **Standard Go build**
- **Go build with Garble**

Both approaches are valid; however, building with Garble provides additional benefits that are important to consider.

## **Why Build with Garble?**

[**Garble**](https://github.com/burrowers/garble) is a tool that works as a compiler wrapper around go build, designed to **obfuscate** Go code. Here’s why we encourage you to use it:

- **Obfuscation**: Garble reduces the risk of reverse-engineering by renaming symbols, stripping debug information, and minimizing the visibility of the internal structure of your binaries.
- **Security**: Protects proprietary algorithms, sensitive logic, and API interactions from easy inspection.
- **Reduced Binary Predictability**: Makes the binary less predictable, which can deter certain types of static analysis or targeted attacks.
- **Minimal Overhead**: Garble integrates easily into the Go toolchain without major changes to your build pipeline.

**Important**: Garble is best used in release builds. For development, we recommend using standard go build for faster build times and better debuggability.

## **How to Build with Go**

To build your project normally

:::BlockQuote
go build -o your-program
:::

This will produce a standard Go binary without any obfuscation.

## **How to Build with Garble**

First, install Garble if you haven’t already:

:::BlockQuote
go install mvdan.cc/garble\@latest
:::

Then build your project with Garble:

:::BlockQuote
garble build -o your-program
:::

This will produce an obfuscated binary, making your application harder to reverse-engineer.

### **Additional Garble Options**

Garble offers several options to fine-tune the obfuscation process. Some recommended flags:

- -`literals`: Obfuscates literals like strings and numbers.
- -`tiny`: Reduces binary size further and increases obfuscation.
- -`debug`: Enables some debug features (not recommended for production).

Example with extra obfuscation:

:::BlockQuote
garble -literals -tiny build -o your-program
:::

## **Summary**

| **Build Method** | **Pros**                                           | **Cons**                                  |
| ---------------- | -------------------------------------------------- | ----------------------------------------- |
| go build         | Fast, easy, debuggable                             | No protection against reverse engineering |
| garble build     | Obfuscated, more secure, less predictable binaries | Slightly slower builds, harder to debug   |


[title] Whitelabeling
[path] Floating Server/Floating Server V1/Best Practices/

## Logo

LicenseSpring's floating server implementation allows you to add your company's logo to each floating server deployment by doing the following:

1. Copy logo path (absolute or relative)
2. Set `logo` argument: `--logo /etc/logo.png`

If using a floating server Helm Chart, check [**https://artifacthub.io/packages/helm/floating-server/floating-server**](https://artifacthub.io/packages/helm/floating-server/floating-server).

Logo dimensions: height \< 60px, width \< 150px

## API and Management URL

You can also customize the API and management URLs of the Floating Server to use your own domain. An example configuration in the `config.yaml` file:

```yaml
apiUrl: https://subdomain.YOUR_WHITLABEL_DOMAIN.tld
managementUrl: https://subdomain.YOUR_WHITLABEL_DOMAIN.tld
```

By default, these URLs are set to LicenseSpring’s API, but for single-tenancy clients or custom solutions, you can override these values.&#x20;

[title] Hardware ID
[path] SDKs/node.js SDK/

Both LicenseAPI and LicenseManager use the Hardware ID module to calculate a unique fingerprint for the local machine. The module provides multiple methods of determining the ID:

```typescript
export enum HardwareIdAlgorithm {
  Default = 0,
  WindowsHardwareFingerprintId = 1,
  WindowsComputerSystemProductId = 2,
  WindowsCryptographyId = 3,
  LinuxMachineId = 4,
  CloudPlatformsId = 5,
};
```

The default method (0) covers all cases and fallbacks. If you override the default method, the method used should be consistent accross your project. For both LicenseAPI and LicenseManager, this can be overriden globally by setting the required value in the config object when initializing the LicenseAPI/LicenseManager, e.g.:

```javascript
const licenseAPI = new LicenseAPI({
  apiKey: '12345678-4bfe-4e3a-8737-757004d6294c',
  sharedKey: 'eYuHrlajvIVTiSFIXpxpKhw78f4Ewy-00-12345678',
  appName: 'js-sdk-test-1',
  appVersion: '0.0.1',
  hardwareIDMethod: 5,
});
```


[title] Android SDK
[path] SDKs/

To include the Android SDK in your maven project define a link to our repository and dependency like shown below.

```xml
     <dependencies>
        <dependency>
            <groupId>com.licensespring</groupId>
            <artifactId>androidsdk</artifactId>
            <version>1.5.0</version>
        </dependency>

    </dependencies>

    <repositories>
        <repository>
            <id>androidsdk</id>
            <url>https://licensespring-android-sdk.s3.amazonaws.com/</url>
        </repository>
    </repositories>
```

If your are using gradle to build your projects, you can include the dependencies for LicenseSpring with the following snippet:

```java
repositories {
    mavenLocal()
    maven {
         url "https://licensespring-android-sdk.s3.amazonaws.com"
    }
}

dependencies {
    implementation (group: 'com.licensespring', name: 'androidsdk', version: '1.5.0', ext: 'aar', classifier: 'release') {
		transitive=true
    }
}
```

:::hint{type="danger"}
Minimum Android version for this SDK is 8.1 (Orea - API level 27)
:::

Javadoc can be downloaded here:

::File[]{src="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/dtB9Juu2mtlKsLwu2JAS6_licensespring-android-docs-11.zip" signedSrc="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/dtB9Juu2mtlKsLwu2JAS6_licensespring-android-docs-11.zip?AWSAccessKeyId=AKIAYQNQCIXNIQWBC56C&Expires=1702553772&Signature=uofgUG1pTb98%2BGvYKa3jbFNscPc%3D" label="licensespring-android-docs-1.1.zip"}

## Release Notes:

## December 12th, 2023, v1.5.0

**Floating Features**

**FloatingService**:

- Ad&#x64;**&#x20;checkLicenseFeature&#x20;**&#x6D;ethod
- Ad&#x64;**&#x20;releaseFloatingFeature&#x20;**&#x6D;ethod

**LicenseService**:

- Ad&#x64;**&#x20;checkLicenseFeature&#x20;**&#x6D;ethod

## October 12th, 2023, v1.4.0

- Floating License

## April 28th, 2023, v1.3.0

- support 'YYYY-MM-DD' date time format in response
- fixed product details response

## April 19th, 2023, v1.2.0

- fixed air gap license activation code
- fixed air gap license verify
- changed activateAirGapResponse method signature to be able to load policy file from res/raw folder

## February 22nd, 2023, v1.1.8

- fixed consumtion license check

## January 30th, 2023, v1.1.7

- remove unused BouncyCastle provider in AirGappedService

## January 19th, 2023, v1.1.6

- updated java sdk version in config for license tracking (showed up as 1.1.1 until now)

## January 16th, 2023, v1.1.5

- removed BouncyCastle provider for AirGap - use default provider

see [**https://android-developers.googleblog.com/2018/03/cryptography-changes-in-android-p.html**](https://android-developers.googleblog.com/2018/03/cryptography-changes-in-android-p.html) for more info about this change

## January 10th, 2023, v1.1.4

- added support for multiple licences on the same device. Added the LicenseManagerFactory for creating multiple LicenseManager objects (one for each different license)
- added support for offline user-based licences

## November 4th, 2022, v1.1.3

- added AirGappedService and LicenseSpringManager methods: `getAirGapActivationCode`, `verifyAirGapConfirmationCode`, `activateAirGapResponse`

## August 19th, 2022, v1.1.2

- added reinitialize() method - for changing the configuration during runtime

## August 10th, 2022, v1.1.1

- Added toggleable offlineMode - to change offline mode in runtime

## June 14th, 2020, v1.1

- Exposed JsonSerialization class.
- Fixed bug with daysRemaining method on License. SUBSCRIPTION license returned max days, instead of CONSUMPTION type.
- Fixed issue with locale datetime support.
- Implemented periodic license check - can be enabled via configuration.
- Added request logging options, default is OFF/NONE.
- Refactored Offline license code from LicenseRepository into a separate class .
- LicenseRepository is now an interface SDK users can implement.
- Added an intitialize() method overload on LicenseSpringManager which accepts the LicenseRepository as the second parameter.
- Added the default implementation of LicenseRepository, no SDK users will not need to change their implementation, unless building a custom LicenseRepository.

## May 11th, 2020, v1.0

Initial Release of the LicenseSpring Android SDK.

[title] Proxy
[path] SDKs/node.js SDK/

All calls to the server can be proxied by providing a proxy definition in either of the following two ways:

### Option 1

By providing a proxy definition in the initialization config argument for LicenseAPI, LicenseManager and FloatingAPI, e.g.:

```javascript
const licenseAPI = new LicenseAPI({
  apiKey: '12345678-4bfe-4e3a-8737-757004d6294c',
  sharedKey: 'eYuHrlajvIVTiSFIXpxpKhw78f4Ewy-00-12345678',
  appName: 'js-sdk-test-1',
  appVersion: '0.0.1',
  proxy: {
    host: '127.0.0.1',
    port: 9000,
  },
});
```

### Option 2

By by calling the `setProxy` method on an initialized `LicenseAPI`, `LicenseManager` or `FloatingAPI` object, e.g.:

```javascript
licenseAPI.setProxy({
  host: '127.0.0.1',
  port: 9000,
});
```

For the type declaration of the proxy definition object, see `AxiosProxyConfig` in the [**Type Declarations**](docId\:MZZqruPoqeqxNUuWSxNiZ) article.

[title] UI Configuration
[path] Floating Server/Floating Server V1/User Interface/

The Configuration page in the Floating Server’s UI provides a user-friendly interface for customizing server settings. Through this interface, you can easily configure key aspects of your server by performing tasks such as:

- [**Products**](docId\:rsWCrpnQ1XajOtkPdHRHr)&#x20;
- [**Generate Offline License**](docId\:l7jqMuSTfDjuaHc_Ggxj2)
- [**Air-Gap License Activation**](docId\:Gu7iu9OlIugdXxM_YuXW-)
- [**Change Password**](docId\:pMCs_jYe70tHLL9Opv-Fi)&#x20;
- [**Settings**](docId\:fGGMD-VH-Wu6KlKb-myHN)&#x20;



![Products Configuration Page ](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/o47QYfxqCx9fj2TcUloMj_untitled-design.png "Products Configuration Page ")

For more detailed information about each configuration option, please refer to the subpages dedicated to each specific tab.




[title] API Reference
[path] Floating Server/Floating Server V1/


[title] Configuration
[path] Floating Server/Floating Server V1/Deployment Methods/

## Choosing Configuration Type

::figma[]{url="https://www.figma.com/embed?embed_host=archbee&url=https%3A%2F%2Fwww.figma.com%2Ffile%2FCW3McmTMAAwdWOez4NRcNg%2FConfiguration%3Ftype%3Dwhiteboard%26node-id%3D0%253A1%26t%3D5zJTLY4U4IYzcOp1-1"}

### Floating Server UI

Check out our [**User Interface**](docId\:KHO_GHkOeaEgScbTCaD23) documentation to discover how to configure a floating server using the user interface.

### Configuration File

The Floating Server can also rely on a `config.yaml` file to define its operational settings. This file allows you to customize various aspects of the server, including database selection, API keys, and product licenses. For more information, see [**Configuration File**](docId\:QHWax01fYGKmU_ApnXZ2A)&#x20;

[title] Change Password
[path] Floating Server/Floating Server V1/User Interface/UI Configuration/

Change password tab allows you to change the password for Floating server. This is also configurable through the [**Configuration File**](docId\:QHWax01fYGKmU_ApnXZ2A).

If initial password wasn't set, default password is "admin".



::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/5E91hZ_MfJvYw5zP6VGIn_screenshot-2023-06-21-at-143128.png" signedSrc size="80" width="1630" height="504" position="center" caption="Change Password Page" alt="Change Password Page"}


[title] Kubernetes (Helm)
[path] Floating Server/Floating Server V1/Deployment Methods/

The Floating Server can also be deployed using Helm for Kubernetes, offering an automated and scalable solution for enterprise environments. This method is perfect for users who need orchestration and simplified management of the Floating Server within a Kubernetes cluster.&#x20;

Explore the [**Installation Steps**](docId\:emgPowDE2ERx7nfQjG0ar) to learn how to set up the LicenseSpring Floating Server using Helm for Kubernetes, and visit the [**Troubleshooting**](docId\:QFDljgv1mgzDxusRktAp2) section for answers to common questions.&#x20;

[title] Set Password
[path] Floating Server/Floating Server V1/API Reference/config/

{
  "id": "hR67uOa7P_PiDl-jrA64J",
  "data": {
    "url": "http://localhost:8080/api/v4/setPassword",
    "name": "Set Password",
    "method": "GET",
    "request": {
      "pathParameters": [],
      "queryParameters": [
        {
          "kind": "optional",
          "name": "passwordOld",
          "type": "string",
          "description": "<p>Old password, used for verification</p>"
        },
        {
          "kind": "optional",
          "name": "passwordNew",
          "type": "string"
        }
      ],
      "headerParameters": [],
      "bodyDataParameters": [],
      "formDataParameters": []
    },
    "responses": [
      {
        "statusCode": "200",
        "description": "",
        "jsonExample": ""
      }
    ],
    "contentType": "application/json",
    "description": "Set new password"
  },
  "type": "api-oas-v2",
  "children": [
    {
      "id": "fd_QPRZsaII1EhJsiOI74",
      "type": "paragraph",
      "children": [
        {
          "text": "Set new password"
        }
      ]
    }
  ]
}
[title] Executable
[path] Floating Server/Floating Server V1/Deployment Methods/

The Floating Server is available as an executable that can be easily downloaded and run on Windows, macOS, or Linux. This method is ideal for users seeking a straightforward, self-contained deployment solution for managing licenses on-premise.

Visit [**Installation Steps**](docId\:jrJIreTPB1wNbhC-Uxu_a) to explore how to setup the LicenseSpring Floating Server using an executable and [**Troubleshooting**](docId:9kvNx0Wd7apGHrEdZC_2w) for answers to some of the most frequently asked questions!

[title] Settings
[path] Floating Server/Floating Server V1/User Interface/UI Configuration/

Settings tab is used for general configuration for Floating Server. Currently, it is used to configure:

- API key
- Shared key
- License API URL
- Management API URL

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/INLfk8BIB_taAdesmjijd_image.png" signedSrc size="66" width="463" height="562" position="center" caption}


[title] Registrations
[path] Floating Server/Floating Server V1/User Interface/

The Registrations section of the Floating Server provides a comprehensive overview of how licenses are registered, consumed, and managed. This area is crucial for ensuring that licenses are allocated properly and that consumption is tracked in accordance with your licensing model.

You can navigate through two key areas in the Registrations section:

- [**Registration List**](docId\:ClmyzIo1d5zWM1oVsHgSK):
  This page offers detailed statistics on license registrations, including the total number of active registrations per product and information on individual registrations. You can also manage registrations, allowing for flexibility when reassigning licenses.&#x20;
- [**Consumption List**](docId\:mdaAo-QlZjACjWn0q7dNF):
  This page manages the consumption of licenses and features. It allows you to track the usage of your licenses, ensuring that the consumption limits and any overages are handled appropriately.&#x20;


[title] Deployment Methods
[path] Floating Server/Floating Server V1/

Floating servers can be deployed on multiple platforms:&#x20;

- [**Kubernetes (Helm)**](docId\:Pf5ciOZrNmrcQlXTLaeJD) (and OpenShift)
- [**Docker**](docId\:F6_e9q0DteogfAhmR997-)&#x20;
- Using an [**Executable**](docId\:nUigSoDmRuiadQA-MtJe1)&#x20;

Following are flowcharts which can help you decide which type of deployment is best suited for your use case.

::figma[]{url="https://www.figma.com/embed?embed_host=archbee&url=https%3A%2F%2Fwww.figma.com%2Ffile%2FISMqHKPcMYginlNucOnh7n%2FUntitled%3Ftype%3Dwhiteboard%26node-id%3D0%253A1%26t%3Dpwv7KHOP3movWcI6-1"}

::figma[]{url="https://www.figma.com/embed?embed_host=archbee&url=https%3A%2F%2Fwww.figma.com%2Ffile%2Fu7sN6jYwor2UvOKhAXzgwY%2FDeployment-process%3Ftype%3Dwhiteboard%26node-id%3D0%253A1%26t%3DmaF8Cg7T4ZwO4J3I-1"}


[title] Storage Requirements
[path] Floating Server/Floating Server V1/Deployment Methods/Configuration/

The Floating Server is designed with a light footprint in mind, ensuring that it remains efficient and unobtrusive in various operational environments.

**1. Badger Database:**&#x20;

The Badger database starts with a pre-configured allocation of 102 megabytes, optimized for minimal impact while providing ample storage for typical usage. This size can accommodate the standard data load with significant room for growth, although exceeding this capacity is rare. Typically, surpassing the 100-megabyte threshold would require the storage of over 100,000 data points, a scenario unlikely under normal operational conditions.

**2. Redis Database:**

The Redis database starts with a negligible initial footprint and is designed to scale efficiently with data addition. Extensive testing has demonstrated that even with up to 10,000 data points, the database consumes less than 5 megabytes of storage. This consistent performance affirms our expectation that the Redis database will comfortably remain well under 100 megabytes for standard usage, ensuring optimal efficiency and resource management.&#x20;

[title] User Interface
[path] Floating Server/Floating Server V1/

The Floating Server UI provides a user-friendly interface for interacting with the Floating Server. It offers several pages for managing various aspects of the server, each explained in more detail within the corresponding subpages.

The home page of the Floating Server includes navigation to all these sections and can be accessed via the URL [**http://localhost:8080/**](http://localhost:8080/) after starting the server.

![Floating Server Home Page](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/wAz3zvdjXJzUKsUl2v1Px_screenshot-2023-06-21-at-144122.png "Floating Server Home Page")


[title] License API
[path] SDKs/node.js SDK/

Provides a direct interface to the [**LicenseSpring API**](https://docs.licensespring.com/license-api/). The LicenseAPI class encapsulates API calls, input checks, authentication and signature verification. Typescript definitions are provided for the arguments and return types of the class methods.

To import the LicenseAPI class use:

```javascript
const { LicenseAPI } = require('@licensespring/node-sdk');
```

### Creating an instance

```javascript
const licenseAPI = new LicenseAPI({
  apiKey: '12345678-4bfe-4e3a-8737-757004d6294c',
  sharedKey: 'eYuHrlajvIVTiSFIXpxpKhw78f4Ewy-00-12345678',
  appName: 'js-sdk-test-1',
  appVersion: '0.0.1',
  /** NOTE: the following properties are set to their default values by the SDK and can be overriden manually: */
  // apiPath: 'http://api.dev.licensespring.com/api/v4',
  // publicKey: '...',
});
```

The constructor takes the a single argument of the following type:

```typescript
{
  /** your Licensespring API key */
  apiKey: string,
  /** your Licensespring API Shared key **/
  sharedKey: string,
  /** custom name for your application */
  appName: string,
  /** custom version string for your application */
  appVersion: string,
  /** your Air Gap Activation key (optional) */
  airGapKey?: string,
  /** override for License API url (default is https://api.licensespring.com/api/v4/) **/
  apiPath?: string,
  /** override for License API public key (default is pub key for api.licensespring.com) **/
  publicKey?: string,
  /** override for License File filename (default is "License") */
  filename?: string,
  /** override for License File path (default is current directory) */
  filePath?: string,
  /** override for License File encryption key */
  fileKey?: string,
  /** override for license grace period duration in hours (default is 24) */
  gracePeriod?: number,
  /** override for License File guard file (default is false) */
  isGuardFileEnabled?: boolean,
  /** override for Hardware ID calculation method (default is 0, for more info see "Hardware ID" section) */
  hardwareIDMethod?: number,
  /** a custom provided Hardware ID (overrides HWID calculation) */
  hardwareID?: string,
}
```

## API methods

For type declarations see [**Type Declarations**](https://www.npmjs.com/package/@licensespring/node-sdk#types).

### Hardware ID

Generates a [**Hardware ID**](https://www.npmjs.com/package/@licensespring/node-sdk#hardware-id). This value is required for various API method calls.

If the optional argument is not provided, it defaults to the value set in the configuration object provided when instantiating the LicensespringAPI object. If no value was provided in the config object, it defaults to 0 (the default Hardware ID method).

```typescript
getHardwareID(algorithm?: HardwareIdAlgorithm): string
```

### Check License

See: [**Check License**](docId\:Zh4KFIh_s59TzIBZKeb9o)&#x20;

```typescript
checkLicense(
  payload: CheckLicensePayload, 
  includeExpiredFeatures: boolean = false
): Promise<CheckLicenseResponse>

type CheckLicensePayload = ({
  username: string;
} | {
  license_key: string;
}) & {
  product: string;
  hardware_id: string;
  env: string | undefined;
  license_id: number | undefined;
  sdk_ver: string | undefined;
  app_ver: string | undefined;
  hostname: string | undefined;
  os_hostname: string | undefined;
  ip_local: string | undefined;
  mac_address: string | undefined;
  ip: string | undefined;
  os_ver: string | undefined;
  channel: string | undefined;
};

type CheckLicenseResponse = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  allow_offline_activation: boolean,
  can_borrow: boolean,
  custom_fields: CustomField[],
  customer: CustomerResponse,
  enable_maintenance_period: boolean,
  floating_timeout: number,
  floating_users?: number,
  grace_period: number | null,
  is_air_gapped: boolean,
  is_floating: boolean,
  is_floating_cloud: boolean,
  is_hardware_key_auth: boolean,
  license_key: string | undefined,
  license_template_id?: number,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users?: number,
  max_overages: number,
  max_transfers?: number,
  metadata: JSONObjectRequired,
  metadata_string?: string,
  order_store_id?: string,
  prevent_vm: boolean,
  company: {
    id: number,
  },
  product_details?: ProductDetailsResponse,
  product_features: FeatureResponse[],
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null,
  is_trial: boolean,
  trial_days?: number,
  user?: LicenseUserResponse,
  license_type: LicenseTypes,
  allow_negative_consumptions?: boolean,
  allow_unlimited_consumptions?: boolean,
  consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
  max_consumptions?: number,
  reset_consumption?: boolean,
  total_consumptions?: number,
  borrowed_until: string | null,
  floating_in_use_devices?: number,
  is_borrowed: boolean,
  is_expired: boolean,
  license_active: boolean,
  license_enabled: boolean,
  license_signature: string,
};
```

### Check License Offline

Checks an offline license file

```typescript
checkLicenseOffline(payloadBase64: string): Promise<LicenseFilePayload>

type LicenseFilePayload = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  allow_offline_activation: boolean,
  can_borrow: boolean,
  custom_fields: CustomField[],
  customer: CustomerResponse,
  enable_maintenance_period: boolean,
  floating_timeout: number,
  floating_users?: number,
  grace_period: number | null,
  is_air_gapped: boolean,
  is_floating: boolean,
  is_floating_cloud: boolean,
  is_hardware_key_auth: boolean,
  license_key: string | undefined,
  license_template_id?: number,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users?: number,
  max_overages: number,
  max_transfers?: number,
  metadata: JSONObjectRequired,
  metadata_string?: string,
  order_store_id?: string,
  prevent_vm: boolean,
  company: {
    id: number,
  },
  product_details?: ProductDetailsResponse,
  product_features: FeatureResponse[],
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null,
  is_trial: boolean,
  trial_days?: number,
  user?: LicenseUserResponse,
  license_type: LicenseTypes,
  allow_negative_consumptions?: boolean,
  allow_unlimited_consumptions?: boolean,
  consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
  max_consumptions?: number,
  reset_consumption?: boolean,
  total_consumptions?: number,
  request: string,
  active: boolean,
  device_id: number,
  validity_period: string | null,
  is_expired: boolean,
  hardware_id: string,
  username?: string,
  max_license_users?: number,
  is_floating_cloud: boolean,
  floating_in_use?: boolean,
  license_signature: string,
  variables?: ({
    value: string;
    device_id: number;
    variable: string;
    created_at: string | null;
  })[];
  date: string,
  offline_signature: string,
  date: string,
  offline_signature: string,
  license_signature_v2: string,
  offline_signature: string,
};
```

### Check Bundle

See: [**Check Bundle**](docId\:odudSbU1BNxycgT4zx8FW)&#x20;

```typescript
checkBundle(
  payload: CheckBundlePayload, 
  includeExpiredFeatures: boolean = false
): Promise<CheckBundleResponse>

type CheckBundlePayload = ({
  username: string;
} | {
  license_key: string;
}) & {
  product: string;
  hardware_id: string;
  env: string | undefined;
  license_id: number | undefined;
  sdk_ver: string | undefined;
  app_ver: string | undefined;
  hostname: string | undefined;
  os_hostname: string | undefined;
  ip_local: string | undefined;
  mac_address: string | undefined;
  ip: string | undefined;
  os_ver: string | undefined;
  channel: string | undefined;
};

type CheckBundleResponse = CheckLicenseResponse[];
// see CheckLicenseResponse declaration in "Check License" section above
```

### Check Bundle Offline

Checks an offline bundle license file

```typescript
checkBundleOffline(payloadBase64: string): Promise<Record<string, LicenseFilePayload>>

// see LicenseFilePayload declaration in "Check License Offline" section above
```

### Activate License Online

See: [**Activate License (Online Method)**](docId\:Mt2yGm6CJzh2bumU-Gfww)&#x20;

```typescript
activateLicense(payload: ActivateLicensePayload): Promise<ActivateLicenseResponse>

type ActivateLicensePayload = ({ 
  license_key: string; 
} | {
  username: string;
  password: string;
} | {
  code: string;
  customer_account_code: string;
} | {
  id_token: string;
  customer_account_code: string;
}) & {
  hardware_id: string;
  product: string;
  variables: { [key: string]: string | number | boolean } | undefined;
};

type ActivateLicenseResponse = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  allow_offline_activation: boolean,
  can_borrow: boolean,
  custom_fields: CustomField[],
  customer: CustomerResponse,
  enable_maintenance_period: boolean,
  floating_timeout: number,
  floating_users?: number,
  grace_period: number | null,
  is_air_gapped: boolean,
  is_floating: boolean,
  is_floating_cloud: boolean,
  is_hardware_key_auth: boolean,
  license_key: string | undefined,
  license_template_id?: number,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users?: number,
  max_overages: number,
  max_transfers?: number,
  metadata: JSONObjectRequired,
  metadata_string?: string,
  order_store_id?: string,
  prevent_vm: boolean,
  company: {
    id: number,
  },
  product_details?: ProductDetailsResponse,
  product_features: FeatureResponse[],
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null,
  is_trial: boolean,
  trial_days?: number,
  user?: LicenseUserResponse,
  license_type: LicenseTypes,
  allow_negative_consumptions?: boolean,
  allow_unlimited_consumptions?: boolean,
  consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
  max_consumptions?: number,
  reset_consumption?: boolean,
  total_consumptions?: number,
  request: string,
  active: boolean,
  device_id: number,
  validity_period: string | null,
  is_expired: boolean,
  hardware_id: string,
  username?: string,
  max_license_users?: number,
  is_floating_cloud: boolean,
  floating_in_use?: boolean,
  license_signature: string,
  variables?: ({
    value: string;
    device_id: number;
    variable: string;
    created_at: string | null;
  })[];
};
```

### Deactivate License Online

See: [**Deactivate License (Online Method)**](docId\:IEcDUEuMOsLwN4biictdc)&#x20;

```typescript
deactivateLicense(payload: ({  
  username: string;
} | {
  license_key: string;
}) & {
  product: string;
  hardware_id: string;
}): Promise<boolean>
```

### Activate License Offline

See: [**Activate License (Offline Method)**](docId\:H_VEWmE7rYJ7QfbIKvGuP)&#x20;

```typescript
activateOffline(payload: string): Promise<ActivateOfflineResponse>

type ActivateOfflineResponse = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  allow_offline_activation: boolean,
  can_borrow: boolean,
  custom_fields: CustomField[],
  customer: CustomerResponse,
  enable_maintenance_period: boolean,
  floating_timeout: number,
  floating_users?: number,
  grace_period: number | null,
  is_air_gapped: boolean,
  is_floating: boolean,
  is_floating_cloud: boolean,
  is_hardware_key_auth: boolean,
  license_key: string | undefined,
  license_template_id?: number,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users?: number,
  max_overages: number,
  max_transfers?: number,
  metadata: JSONObjectRequired,
  metadata_string?: string,
  order_store_id?: string,
  prevent_vm: boolean,
  company: {
    id: number,
  },
  product_details?: ProductDetailsResponse,
  product_features: FeatureResponse[],
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null,
  is_trial: boolean,
  trial_days?: number,
  user?: LicenseUserResponse,
  license_type: LicenseTypes,
  allow_negative_consumptions?: boolean,
  allow_unlimited_consumptions?: boolean,
  consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
  max_consumptions?: number,
  reset_consumption?: boolean,
  total_consumptions?: number,
  request: string,
  active: boolean,
  device_id: number,
  validity_period: string | null,
  is_expired: boolean,
  hardware_id: string,
  username?: string,
  max_license_users?: number,
  is_floating_cloud: boolean,
  floating_in_use?: boolean,
  license_signature: string,
  variables?: ({
    value: string;
    device_id: number;
    variable: string;
    created_at: string | null;
  })[];
  date: string,
  offline_signature: string,
  license_signature_v2: string,
};
```

### Deactivate License Offline

See: [**Deactivate License (Offline Method)**](docId\:iyg1DXIYqp9vW-Mlj-xUk)&#x20;

```typescript
deactivateOffline(payload: string): Promise<boolean>
```

### Activate Bundle Online

See: [**Activate Bundle (Online Method)**](docId\:sj4ujBbDqwMf3QJDVNHdh)&#x20;

```typescript
activatBundle(payload: ActivateBundlePayload): Promise<ActivateBundleResponse>

type ActivateBundlePayload = ({ 
  license_key: string; 
} | {
  username: string;
  password: string;
} | {
  code: string;
  customer_account_code: string;
} | {
  id_token: string;
  customer_account_code: string;
}) & {
  hardware_id: string;
  product: string;
  variables: { [key: string]: string | number | boolean } | undefined;
};

type ActivateBundleResponse = ActivateLicenseResponse[];
// see ActivateLicenseResponse in "Activate License Online" section above
```

### Deactivate Bundle Online

See: [**Deactivate Bundle (Online Method)**](docId\:nzu6SRyNQLlEd2_-HhvhR)&#x20;

```typescript
deactivateBundle(payload: ({  
  username: string;
} | {
  license_key: string;
}) & {
  product: string;
  hardware_id: string;
}): Promise<boolean>
```

### Get Trial Key

See: [**Trial Key**](docId\:MtAnOsFYJyXU-2M0OVz_a)&#x20;

```typescript
getTrialKey(payload: GetTrialKeyPayload): Promise<TrialResponse>

type GetTrialKeyPayload = {
    sdk_ver: string | undefined;
    email: string | undefined;
    license_policy: string | undefined;
    first_name: string | undefined;
    last_name: string | undefined;
    phone: string | undefined;
    address: string | undefined;
    postcode: string | undefined;
    state: string | undefined;
    country: string | undefined;
    city: string | undefined;
    reference: string | undefined;
    company_name: string | undefined;
    hardware_id: string;
    product: string;
};

type TrialResponse = TrialExistingResponse | TrialNewResponse;

type TrialExistingResponse = {
  license_type: LicenseTypes,
  is_trial: boolean,
  license: string,
} | {
  license_type: LicenseTypes,
  is_trial: boolean,
  license_user: string,
};

type TrialNewResponse = {
  id: number;
  order_id: number;
  product_id: number;
  created_at: number;
  updated_at: number;
  active: boolean;
  enable_maintenance_period: boolean;
  enabled: boolean;
  is_floating: boolean;
  is_hardware_key_auth: boolean;
  is_trial: boolean;
  license_type: LicenseTypes;
  maintenance_duration: string | null;
  max_activations: number;
  max_transfers: number;
  metadata_string: string | undefined;
  metadata: JSONObjectRequired,
  prevent_vm: boolean;
  times_activated: number;
  trial_days: number;
  validity_period?: string;
  company: {
    id: number;
  };
  LicenseProductFeatures: ({
    id: number;
    product_feature_id: number;
    max_consumption: number;
    allow_overages: boolean;
    max_overages: number;
    reset_consumption: boolean;
    consumption_period?: ConsumptionPeriod;
    is_floating: boolean;
    is_floating_cloud: boolean;
    metadata: JSONObjectRequired,
    metadata_string?: string;
    floating_timeout?: number;
    floating_users?: number;
  })[];
  LicenseCustomFields: ({
    product_custom_field_id: number;
    value: string | undefined;
  })[];
  is_floating_cloud: boolean;
  floating_users: number;
  floating_timeout: number;
  allow_overages: boolean;
  max_overages: number;
  max_consumptions: number;
  valid_duration: null;
  consumption_period: ConsumptionPeriod | null;
  reset_consumption?: boolean;
  grace_period: number;
  allow_grace_period: boolean;
} & ({
  license: string;
  license_key: string;
} | {
  license_user: string;
  initial_password: string;
  license_user_id: number | null;
  max_license_users: number;
});
```

### List Licenses for User

See: [**Licenses for User**](docId\:rP314yS1TvcYmB99k7UuV)&#x20;

```typescript
getUserLicenses(payload: GetUserLicensesPayload): Promise<GetUserLicensesResponse>

type GetUserLicensesPayload = ({ 
  license_key: string; 
} | {
  username: string;
  password: string;
} | {
  code: string;
  customer_account_code: string;
} | {
  id_token: string;
  customer_account_code: string;
}) & {
  product?: string;
};

type GetUserLicensesResponse = ({
  
  license: {
    id: number,
    allow_grace_period: boolean,
    allow_overages: boolean,
    allow_unlimited_activations: boolean,
    allow_offline_activation: boolean,
    can_borrow: boolean,
    custom_fields: CustomField[],
    customer: CustomerResponse,
    enable_maintenance_period: boolean,
    floating_timeout: number,
    floating_users?: number,
    grace_period: number | null,
    is_air_gapped: boolean,
    is_floating: boolean,
    is_floating_cloud: boolean,
    is_hardware_key_auth: boolean,
    license_key: string | undefined,
    license_template_id?: number,
    maintenance_period: string | null,
    max_activations: number,
    max_borrow_time: number,
    max_license_users?: number,
    max_overages: number,
    max_transfers?: number,
    metadata: JSONObjectRequired,
    metadata_string?: string,
    order_store_id?: string,
    prevent_vm: boolean,
    company: {
      id: number,
    },
    product_details?: ProductDetailsResponse,
    product_features: FeatureResponse[],
    start_date: string | null,
    times_activated: number,
    transfer_count: number,
    validity_period: string | null,
    is_trial: boolean,
    trial_days?: number,
    user?: LicenseUserResponse,
    license_type: LicenseTypes,
    allow_negative_consumptions?: boolean,
    allow_unlimited_consumptions?: boolean,
    consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
    max_consumptions?: number,
    reset_consumption?: boolean,
    total_consumptions?: number,
    license_active: boolean,
    license_enabled: boolean,
  },
  
  user: {
    id: number,
    email: string,
    first_name: string,
    is_initial_password: boolean,
    last_name: string,
    phone_number: string,
    allow_unlimited_activations?: boolean,
    max_activations?: number,
    total_activations?: number,
  },
})[];
```

### List License Users for Customer

See: [**List License Users for Customer**](docId\:m4Gokma1PFwxAdK0cgLKl)&#x20;

```typescript
getCustomerLicenseUsers(payload: {
    product: string;
    customer: string;
}): Promise<CustomerLicenseUsersResponse>

type CustomerLicenseUsersResponse = {
  company: {
    id: number;
  };
  customer: CustomerResponse;
  users: ({
    email: string | undefined;
    allow_unlimited_activations: boolean;
    first_name: string;
    initial_password: string;
    is_active: boolean;
    is_initial_password: boolean;
    last_name: string;
    license_id: number;
    max_activations: number;
    order_id: number;
    order_store_id: string;
    phone_number: string;
    total_activations: number;
  })[];
};
```

### Check License Feature

See: [**License Feature Check**](docId\:NOL8JafP0APIA6Di6W5vT)

```typescript
checkLicenseFeature(payload: CheckLicenseFeaturePayload): Promise<CheckLicenseFeatureResponse>

type CheckLicenseFeaturePayload = ({
  license_key: string;
} | {
  username: string;
}) & {
  license_id: number | undefined;
  sdk_ver: string | undefined;
  include_metadata_string: boolean | undefined;
  hardware_id: string;
  product: string;
  feature: string;
};

type CheckLicenseFeatureResponse = {
  id: number;
  license_id: number;
  code: string;
  name: string;
  metadata: JSONObjectRequired,
  metadata_string?: string;
  is_floating: boolean;
  is_floating_cloud: boolean;
  floating_in_use_devices?: number;
  expiry_date: string | null;
  feature_type: 'activation';
} | {
  id: number;
  license_id: number;
  code: string;
  name: string;
  metadata: JSONObjectRequired,
  metadata_string?: string;
  is_floating: boolean;
  is_floating_cloud: boolean;
  floating_in_use_devices?: number;
  expiry_date: string | null;
  feature_type: 'consumption';
  consumption_period: ConsumptionPeriod;
  allow_negative_consumptions: boolean;
  allow_overages: boolean;
  allow_unlimited_consumptions: boolean;
  max_consumption: number;
  max_overages: number;
  reset_consumption: boolean;
  total_consumptions: number;
};
```

### Add License Consumption

See: [**Add Consumption**](docId\:SRwB9sGGWhqXqncym3TBi)&#x20;

```typescript
addConsumption(payload: AddConsumptionPayload): Promise<AddConsumptionResponse>

type AddConsumptionPayload = ({
  license_key: string;
} | {
  username: string;
}) & {
  product: string;
  hardware_id: string;
  consumptions: number;
  sdk_ver: string | undefined;
  license_id: number | undefined;
  ignore_events: boolean | undefined;
  allow_overages: boolean | undefined;
  max_overages: number | undefined;
  event: ("consumption_add" | "offline_floating_consumptions_sync")[] | undefined;
};

type AddConsumptionResponse = {
  id: number;
  max_consumptions: number;
  allow_unlimited_consumptions: boolean;
  allow_negative_consumptions: boolean;
  allow_overages: boolean;
  max_overages: number;
  reset_consumption: boolean;
  consumption_period: ConsumptionPeriod | undefined;
  total_consumptions: number;
  company: {
    id: number;
  };
};
```

### Add License Feature Consumption

See: [**Add Feature Consumption**](docId\:VP8t3pHTtDPQ46i9YKtFF)&#x20;

```typescript
addFeatureConsumption(payload: AddFeatureConsumptionPayload): Promise<AddFeatureConsumptionResponse>

type AddFeatureConsumptionPayload = ({
  license_key: string;
} | {
  username: string;
}) & {
  product: string;
  hardware_id: string;
  consumptions: number;
  feature: string;
  sdk_ver: string | undefined;
  license_id: number | undefined;
  ignore_events: boolean | undefined;
  allow_overages: boolean | undefined;
  max_overages: number | undefined;
  event: ("consumption_add" | "offline_floating_consumptions_sync")[] | undefined;
};

type AddFeatureConsumptionResponse = {
  id: number;
  license_id: number;
  company: {
    id: number;
  };
  total_consumptions: number;
  max_consumptions: number;
  allow_negative_consumptions: boolean;
  allow_unlimited_consumptions: boolean;
  allow_overages: boolean;
  max_overages: number;
  reset_consumption: boolean;
  consumption_period: ConsumptionPeriod;
  is_floating: boolean;
  is_floating_cloud: boolean;
  floating_timeout?: number;
  floating_users?: number;
};
```

### Get Product Details

See: [**Get Product Details**](docId\:AR0IgR0c1_Dvx1yn044RR)&#x20;

```typescript
getProductDetails(payload: ProductDetailsPayload): Promise<GetProductDetailsResponse>

type ProductDetailsPayload = {
    product: string;
    include_latest_version: boolean | undefined;
    include_custom_fields: boolean | undefined;
    env: string | undefined;
};

type GetProductDetailsResponse = {
  product_id: number,
  product_name: string,
  short_code: string,
  allow_trial: boolean,
  trial_days: number,
  authorization_method: AuthorizationMethod,
  floating_timeout: number,
  allow_overages: boolean,
  max_overages: number,
  prevent_vm: boolean,
  metadata: JSONObjectRequired,
  metadata_string?: string,
  company: {
    id: number
  },
  latest_version?: {
    id: number;
    version: string | undefined;
    full_link: string | undefined;
    filename: string | undefined;
    release_date: string | null;
    hash_md5: string | undefined;
    environment: string;
    eula_link: string | undefined;
    release_notes_link: string | undefined;
    size: string | undefined;
    requires_version: string | undefined;
    channel: string | undefined;
    created_at: string | null;
    updated_at: string | null;
    enabled: boolean;
    product_id: number;
  } | null,
  custom_fields?: { id: number, name: string, default_value: string }[]
};
```

### Get Device Variables

See: [**Get Device Variables**](docId\:ZjVswpdxa3gR_9kIq0Gng)&#x20;

```typescript
getDeviceVariables(payload: GetDeviceVariablesPayload): Promise<GetDeviceVariablesResponse>

type GetDeviceVariablesPayload = ({
    license_key: string;
} | {
    username: string;
}) & {
    product: string;
    hardware_id: string;
    sdk_ver: string | undefined;
    license_id: number | undefined;
};

type GetDeviceVariablesResponse = {
  id: number;
  created_at: string;
  variable?: string;
  value?: string;
  device_id: number;
}[];
```

### Track Device Variables

See: [**Track Device Variables**](docId:9lCvdjjD_nsJUu7UibEaA)&#x20;

```typescript
trackDeviceVariables(payload: TrackDeviceVariablesPayload): Promise<TrackDeviceVariablesResponse>

type TrackDeviceVariablesPayload = ({
    license_key: string;
} | {
    username: string;
}) & {
    product: string;
    hardware_id: string;
    variables: { [key: string]: string | number | boolean },
    sdk_ver: string | undefined;
    license_id: number | undefined;
};

type TrackDeviceVariablesResponse = {
  variable: string;
  value: string;
  device_id: number;
  created_at: number;
}[];
```

### Borrow Floating License

See: [**Borrow Floating License**](docId\:SoOypvnWqodzw1rTwyuST)&#x20;

```typescript
floatingBorrow(payload: FloatingBorrowPayload): Promise<FloatingBorrowResponse>

type FloatingBorrowPayload = ({
    license_key: string;
} | {
    username: string;
    password: string;
}) & {
    product: string;
    hardware_id: string;
    borrowed_until: string | null;
    sdk_ver: string | undefined;
    license_id: number | undefined;
};

type FloatingBorrowResponse = {
  borrowed_until: string | null;
  max_borrow_time: number;
  device_id: number;
  license_id: number;
  company: {
    id: number;
  };
};
```

### Release Floating License

See: [**Release Floating License**](docId\:Ac4QjdmMGxWJRZJv9mRrU)&#x20;

```typescript
floatingRelease(payload: FloatingReleasePayload): Promise<boolean>

type FloatingReleasePayload = ({
    license_key: string;
} | {
    username: string;
}) & {
    product: string;
    hardware_id: string;
    sdk_ver: string | undefined;
    license_id: number | undefined;
};
```

### Release Floating Feature

See: [**Release Floating Feature**](docId\:VySqAv5zovSK4Lj93xVDi)&#x20;

```typescript
featureRelease(payload: FloatingFeatureReleasePayload): Promise<boolean>

type FloatingFeatureReleasePayload = ({
    license_key: string;
} | {
    username: string;
}) & {
    product: string;
    hardware_id: string;
    feature: string;
    sdk_ver: string | undefined;
    license_id: number | undefined;
};
```

### Change Password

See: [**Change Password**](docId\:B4ixyzvAh4TAltTuuajyi)&#x20;

```typescript
changePassword(payload: {
    username: string;
    password: string;
    new_password: string;
}): Promise<boolean>
```

### Get Product Versions

See: [**Get Product Versions**](docId\:mBq0eK4XlT_jX8SLdyHY9)&#x20;

```typescript
getVersions(payload: GetVersionsPayload): Promise<VersionsResponse>

type GetVersionsPayload = ({
    license_key: string;
} | {
    username: string;
}) & {
    product: string;
    hardware_id: string;
    sdk_ver: string | undefined;
    env: string | undefined;
    channel: string | undefined;
};

type VersionsResponse = ({
  version: string | undefined;
  release_date: string | null;
})[];
```

### Get Product Installation File

See: [**Get Installation File**](docId\:LxPe6kV-OLj7HLL-GrL1q)&#x20;

```typescript
getInstallationFile(payload: GetInstallationFilePayload): Promise<InstallationFileResponse>

type GetInstallationFilePayload = ({
    license_key: string;
} | {
    username: string;
}) & {
    product: string;
    hardware_id: string;
    sdk_ver: string | undefined;
    env: string | undefined;
    channel: string | undefined;
    version: string | undefined;
};

type InstallationFileResponse = {
  id: number;
  version: string | undefined;
  installation_file: string | undefined;
  release_date: string | null;
  hash_md5: string | undefined;
  environment: string;
  eula_link: string | undefined;
  release_notes_link: string | undefined;
  size: string | undefined;
  requires_version: string | undefined;
  channel: string | undefined;
  company: {
    id: number;
  };
};
```

### Get Single Sign-On URL

See: [**Single Sign-On URL**](docId\:QbJwnphsDcS0L25UW6PTq)&#x20;

```typescript
getSSOUrl(payload: {
    response_type: 'token' | 'code' | undefined;
    product: string;
    customer_account_code: string;
}): Promise<SSOUrlResponse>

type SSOUrlResponse = {
  url: string;
  openid_configuration: {
    [key: string]: string | number | boolean;
  };
};
```

### Air-Gapped License Code

[**https://docs.licensespring.com/license-entitlements/activation-types/air-gapped**](https://docs.licensespring.com/license-entitlements/activation-types/air-gapped)

```typescript
getAirGapActivationCode(
  initializationCode: string, 
  licenseKey: string
): string

verifyConfirmationCode(
  confirmationCode: string, 
  licenseKey: string, 
  policyId?: string
): boolean

activateAirgappedLicense(
  activationPayload: OfflineActivation, 
  licenseKey: string, 
  policyId: string
): LicenseSaved

type LicenseSaved = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  allow_offline_activation: boolean,
  can_borrow: boolean,
  custom_fields: CustomField[],
  customer: CustomerResponse,
  enable_maintenance_period: boolean,
  floating_timeout: number,
  floating_users?: number,
  grace_period: number | null,
  is_air_gapped: boolean,
  is_floating: boolean,
  is_floating_cloud: boolean,
  is_hardware_key_auth: boolean,
  license_key: string | undefined,
  license_template_id?: number,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users?: number,
  max_overages: number,
  max_transfers?: number,
  metadata: JSONObjectRequired,
  metadata_string?: string,
  order_store_id?: string,
  prevent_vm: boolean,
  company: {
    id: number,
  },
  product_details?: ProductDetailsResponse,
  product_features: FeatureResponse[],
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null,
  is_trial: boolean,
  trial_days?: number,
  user?: LicenseUserResponse,
  license_type: LicenseTypes,
  allow_negative_consumptions?: boolean,
  allow_unlimited_consumptions?: boolean,
  consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
  max_consumptions?: number,
  reset_consumption?: boolean,
  total_consumptions?: number,
  borrowed_until: string | null,
  floating_in_use_devices?: number,
  is_borrowed: boolean,
  is_expired: boolean,
  policy_id: string;
};
```








[title] How To Run Tests
[path] SDKs/Go SDK/v2/Samples/

In addition to the provided samples, there are also **tests** written in the repository. These tests work similarly to the samples but **automatically verify** the correct behavior of the SDK using the **testing** package.&#x20;

### Setup Instructions:

- Create a license with **product code&#x20;**`test`.
  &#x20;This license must support:
  - Online activation
  - Consumption
  - Borrowing
  - Floating cloud
  - It must have available floating slots and consumption units.
  - It must also include a **feature** with:
    - Floating cloud consumption
    - Feature code: `testFeature`
    - Available floating slots and consumption units.

Once that is done, you can run the following tests:

- `TestLicenseConsumption`
- `TestActivateLicense`
- `TestLicenseFeatureConsumption`
- `TestLicenseCheckAndRelease`
- `TestLicenseFeatureCheckAndRelease`
- `TestLicenseFloatingBorrow`

In addition:

- Create a license with **product code&#x20;**`testDisabled`, disable it, and then run:
  - `TestActivateDisabledLicense`
- Create an **expired license** with **product code&#x20;**`testExpired` to run:
  - `TestExpiredLicenseCheck`

These tests automatically activate licenses, update consumptions, check licenses, perform releases, and validate that changes are properly reflected both in the **license response** and **local storage**.

**Important:**
To run the tests correctly, you must **configure your config.yaml** file properly by providing the necessary credentials and license details.

```yaml
clientId: "your-client-id"
clientSecret: "your-client-secret"
cryptoProviderKey: "your-crypto-provider-key" # Required if using OAuth
apiKey: "your-api-key"
sharedKey: "your-shared-key"
verbose: true
verify_signature: true

products:
  productCode1:
    licenseKey: "your-license-key"
  productCode2:
    username: "your-username"
    password: "your-password"
```


[title] Registration List
[path] Floating Server/Floating Server V1/User Interface/Registrations/

## Registrations

The registrations list portion of the registrations page presents the following key statistics:

- **Aggregated Registration Count per Product**:
  This shows the total number of active registrations for each product, allowing you to quickly assess license usage across your entire product portfolio.
- **Individual Registrations**:
  Each active registration is displayed, detailing the specific user or device tied to the license. This helps administrators manage which users or devices have access to licensed software.
- **Aggregated Consumptions per Product**:
  Alongside registrations, the page provides a summary of the current license consumption, indicating how many licenses are in use for each product.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/W9kMGBXX3Bz5U8jP2xh0d_image.png)

## Managing Registrations

By removing a registration, you free up a license, allowing another user to register for that product. This flexibility ensures that licenses can be efficiently reassigned without needing to deactivate or revoke them manually. It's particularly useful in environments with a limited number of licenses and multiple users requiring access.

For example, if a user no longer needs access to a product, their registration can be removed, making the license available for another user or device.

[title] 
[path] SDKs/Go SDK/


[title] Troubleshooting
[path] Floating Server/Floating Server V1/Deployment Methods/Executable/

If your questions are not answered on this page or within the [**FAQ**](docId\:z_8rL9S34hqoUKa58a23h), please [**submit a support ticket**](https://licensespring.zendesk.com/hc/en-us/requests/new) and our support team will respond as soon as possible!

### Issue: Missing or Incorrect Configuration File

**Solution**: Ensure the `config.yaml` file is created and placed in the correct directory. By default, the Floating Server looks for the configuration file in the `config` directory located in the same folder as the executable. If the file is located elsewhere, use the `-config` argument when starting the server:

`./floating-server.exe -config /path/to/config.yaml`

Make sure the `config.yaml` file is correctly formatted, and all required fields (like the database type and API keys) are present.&#x20;

### Issue: Floating Server Not Starting

**Solution**: Ensure the server is running with sufficient permissions. On Linux/macOS, you may need to give execution rights to the binary:

`chmod +x floating-server`

### Issue: Unable to Connect to Redis

**Solution**: Verify that Redis is running and that the connection details in the `config.yaml` file are correct. Make sure the Redis instance is accessible from the machine running the Floating Server:

```yaml
database:
  type: redis
  addresses:
    - localhost:6379
```



If Redis is running on a different machine, ensure the correct IP address and port are provided.&#x20;

### Issue: Floating Server Port Not Available

**Solution**: If the Floating Server is not accessible on the specified port, ensure that the port is not already in use by another application. You can specify a different port in the `config.yaml` file:

```yaml
port: 8080
```

Make sure any firewall or security settings allow incoming connections on the chosen port.&#x20;

### Issue: Logs Not Generated

**Solution**: Ensure the log file location is correctly specified in the `config.yaml` file. The default log file location is `logs/floating-server.log`, but you can specify a custom path:

```yaml
logFile: /path/to/log/file.log
```

Verify that the directory for the log file exists and that the server has write permissions for that directory.&#x20;

### Issue: File-Based Database Not Working

**Solution**: If you're using a file-based database and encountering issues, ensure the `config.yaml` file is set up correctly:

```yaml
database:
  type: file
  addresses:
    - ./database
```

Make sure the specified directory for storing the database files exists and has the appropriate permissions.&#x20;

[title] Installation Steps
[path] Floating Server/Floating Server V1/Deployment Methods/Kubernetes (Helm)/

The Floating Server can be deployed on Kubernetes using Helm charts. To get started:

## **Step 1: Download the Helm Chart**

Get the Helm chart from [**Artifact Hub**](https://artifacthub.io/packages/helm/floating-server/floating-server).

## Step 2: D**eploy with Helm**

Ensure your Redis setup is configured on the Kubernetes cluster. After that, deploy the Floating Server with the Helm chart, specifying the correct values for your environment.

## **Step 3: Monitoring and Scaling**

Set up monitoring using tools like Prometheus and Grafana to observe the server's health. Additionally, configure auto-scaling based on the number of active licenses to ensure optimal performance.


[title] Unity SDK
[path] SDKs/Deprecated SDKs/

## Unity SDK

[**LicenseSpringForUnity\_v1.0.0.unitypackage**](https://sdk-repo.s3.eu-west-1.amazonaws.com/LicenseSpringForUnity_v1.0.0.unitypackage)

:::hint{type="info"}
Platforms support: Windows, OS X, Android, iOS, Linux Unity Support: Unity 2020.3 LTS, Unity 2019.4 LTS, Unity 2018.4 LTS, Unity 2017.4 LTS
:::

:::hint{type="warning"}
Some vendors face issues compiling with the public SDK. This is a known issue with IL2CPP by Xcode for example. Please contact our customer support if you face trouble compiling and we can help you troubleshoot further.
:::

## Release Notes

### April 30, 2021, v1.0.0

- Initial release, based on [**.NET/C# SDK**](docId\:EE620oJMThwCyopGHOMfL)
- Implemented LicenseSpring settings window (Window->LicenseSpring settings OR press F10)
- Implemented LicenseSpring object (Setup data to LicenseSpring window setting or GameObject->LicenseSpring-> API object)
- Implemented LicenseSpring prefab object (License for Unity->Resources->LicenseSpring->Prefabs)
- Added online and offline activation sample scenes


[title] Common
[path] SDKs/Go SDK/v1 (legacy)/

:::hint{type="info"}
LicenseSpring’s new [**Go SDK V2**](docId\:rDJT5fZ-ZkOsGHD5Jso9c)  is now available! This version is a complete rewrite with breaking changes and will receive all future updates and support.

The legacy Go SDK (v1) is deprecated and maintained for backward compatibility only. New users should use v2.
:::

Go SDK is divided into 3 clients:

- Floating client
- License client
- Management client

## Response Types

There are 3 response wrapper types. These are used for future extendability and ease of use.

- Client.Response
- Management\_response.SearchResult
- Error

### Client.Response

Response type is used by all 3 clients, and it's a generic wrapper for any request:

```go
type Response[T any] struct {
	Payload []byte // raw response JSON
	Value   T      // typed value
	Error   error  // error, if it exists
}
```

As an example, license\_client.ActivateLicense would return client.Response\[LicenseResponse], so response.Value would be of type LicenseResponse. Example:

```go
resp := client.ActivateLicense(context.Background(), ...)

// access LicenseResponse fields
resp.Value.LicenseKey

// or get whole LicenseResponse struct
license := resp.Value
license.LicenseKey
```

### Management\_response.SearchResult

SearchResult is used only in management client to wrap search/list request responses. For example, for [**ListCustomers&#x20;**](https://docs.licensespring.com/docs/list-customers)request.

### Error

Error type is commonly used as response for Delete requests, e.g. [**DeleteCustomer**](https://docs.licensespring.com/docs/delete-customer).

[title] Errors and Response Codes
[path] SDKs/

- `active_license_required` (400): active license is required
- `authorization_invalid_headers` (400): invalid headers value in authorization
- `authorization_missing_params` (400): some parameters are missing in authorization: different, parameters&#x20;
- `device_not_found` (400): an active device matching hardware\_id not found
- `hmac_required` (400): hmac is required algorithm
- `internal_error` (500): Server-side error: Internal error
- `invalid_api_key` (400): provided api key is not valid
- `license_activated_max_times` (400): license is already activated max number of times
- `license_key_required` (400): license\_key is missing from the request
- `license_not_active` (400): license is not active
- `license_not_enabled` (400): license is not enabled
- `license_not_found` (400): license with provided license\_key not found
- `missing_hardware_id` (400): hardware\_id missing in the request
- `missing_headers` (400): some headers are missing
- `missing_parameter`s (400): some parameters are missing in the request: different, parameters
- `order_id_exists` (409): Order with this ID already exists
- `signature_mismatch` (401): signature mismatch
- `trial_expired` (400): trial period for device has expired
- `unknown_product` (400): provided product was not found
- `unsupported_product_feature` (400): One or more of requested product features do not exists or they are not enabled on the product
- `version_not_found` (400): file at requested version does not exist
- `disabled_product` (400): Provided product is disabled.
- `archived_product` (400): Provided product is archived.
- `license_transferred_max_times` (400): license transferred max times
- `licenseUserActivatedMaxTimes` (400): license user has already activated license max number of times




[title] Installation
[path] SDKs/node.js SDK/

To install the SDK in your nodejs or typescript project run:

:::BlockQuote
npm i --save @licensespring/node-sdk
:::


[title] Go SDK
[path] SDKs/

:::hint{type="info"}
LicenseSpring’s new [**Go SDK V2**](docId\:rDJT5fZ-ZkOsGHD5Jso9c)  is now available! This version is a complete rewrite with breaking changes and will receive all future updates and support.

The legacy Go SDK (v1) is deprecated and maintained for backward compatibility only. New users should use v2.
:::



Go SDK provides methods to call LicenseSpring APIs directly from Go.

The SDK is publicly available and can be found [**here**](https://gitlab.com/l3178/sdk-go).



### Installation:

`go get -u gitlab.com/l3178/sdk-go/...`

### Specific Versions:

If you want to install a specific version, see the list of versions [**here**](https://gitlab.com/l3178/sdk-go/-/tags). You should preferably always use the latest one.

### Usage Examples:

Usage examples for [**Go License Client**](docId:49m1mYA9TAR5rnZoc5HVf) and [**Management Client**](docId:7oz4ZBjb3qNJz3ASuj2gu) can be found on these docs. Another good source of examples are [**tests**](https://gitlab.com/l3178/sdk-go/-/tree/master/tests).

:::hint{type="danger"}
**Managing API and Shared Keys in the SDK**

The SDK requires the end-user to provide an API key and a shared key for its operation. How these credentials are supplied and managed is up to the user, as it plays a critical role in ensuring security.

While our samples demonstrate using configuration files for convenience, this is only one possible approach. Users may opt for other secure methods, such as environment variables or secret management tools, based on their needs. Regardless of the method chosen, it is essential to implement safeguards to prevent unauthorized access or accidental exposure, especially in public repositories or shared environments.
:::


[title] Floating Server
[path] /

The LicenseSpring Floating Server provides a robust on-premise licensing solution, allowing organizations to manage licenses, features, and consumption both online and offline. [**Version 1&#x20;**](https://docs.licensespring.com/Floating-server/floating-server-v1)offers flexible license management with support for floating license registrations, feature control, usage tracking, and deployment across Windows, macOS, Linux, or containerized environments including Kubernetes. Administrators can configure the server via config.yaml and manage licenses programmatically through the HTTP API.

[**Version 2**](https://docs.licensespring.com/hW11-floating-server-v2) builds on this foundation with a complete rewrite, introducing a modernized architecture powered by the LicenseSpring Go SDK, enhanced reliability, and consistent cloud parity. It features streamlined deployment and configuration, secure server provisioning, flexible storage options with relational databases (SQLite or PostgreSQL), improved synchronization (periodic and on-demand), and a redesigned React-based UI. A key addition in v2 is the **Auto-Generated Configuration File**, which allows admins to provision the server via the Vendor Platform, generate a configuration .YAML file, and download the full certificate chain to reduce misconfiguration risk. Additionally, v2 includes integrated Swagger API documentation, and future plans include multi-vendor support and advanced reporting for deeper insights across server activities. Notably, signature verification is **not supported under FSv1** but is fully supported in **FSv2**, providing an added layer of security for license validation.

[title] Documentation Access
[path] Floating Server/Floating Server V1/User Interface/

The documentation page provides detailed information about the Floating Server API. You can access it either by visiting [**http://localhost:8080/api/v4/docs**](http://localhost:8080/api/v4/docs) or by clicking the **Docs** button on the home page.

![Docs Button on Home Page](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/18qatzDsoYLym3M2umjhM_image.png "Docs Button on Home Page")

![Docs Section in UI](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/NW-HOSi0zO4YTd-FwRzka_image.png "Docs Section in UI")


[title] Online
[path] Floating Server/Floating Server V1/License Options/

Adding a product license online is an essential operation that allows for real-time license activation and management through the Floating Server. Below, you will find the steps to add a license using either the Floating Server API or User Interface.

## Adding with the API

To add a license to the Floating Server, you can use the `/addProduct` API endpoint. This requires passing the product code along with either the license key or username/password combination as query parameters.

To add a license, you need to provide the **product code** along with the required **credentials**. Once the license is successfully added, it will appear in the licenses list, along with its unique **license ID**.

Starting from version 1.6.0:

- Multiple licenses (and corresponding license IDs) can now be associated with a single product code.
- After adding a license, its **license ID** can be used to address the specific license for further actions, as described in the following sections of this documentation.

For more detailed information, visit [**Add license**](docId\:qC90SxDvHS3WMqGi2O2OZ).

## Adding with the User Interface

In the Floating Server UI, you can activate a license online using either **User Authentication** or **Key Authentication**. Follow the steps below based on the authentication method you choose.

### User Authentication

This method requires you to provide the product code, along with the username and password associated with the license.

![Adding a License with User Authentication](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/TbHIENjgjoLp3IUZ48SFk_image.png "Adding a License with User Authentication")

**Steps:**

1. Select **"User auth"** from the dropdown in the **"Add product"** section.
2. Enter the **Product Code**, **Username**, and **Password**.
3. Click **Add** to activate the license.

### Key Authentication

This method requires you to enter the product code and license key.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/WQJZ06NL_JX7QjWFwB2B__image.png)

**Steps:**

1. Select **"Key auth"** from the dropdown in the **"Add product"** section.
2. Enter the **Product Code** and **License Key**.
3. Click **Add** to activate the license.

### Retrieve All Product Licenses

After adding multiple licenses to a product, you can retrieve a complete list of these licenses by sending a GET request to the `/productLicenses`endpoint with the product code provided as a parameter specified by `product`. This endpoint was introduced in version v1.6.0.

:::BlockQuote
http\://\<floating-server>/productLicenses?product=\<your-product>
:::

## How to Refresh&#x20;

To refresh or update an online license, there is no need for a dedicated endpoint or specific location in the UI. You can simply re-add the existing license. For example, if License A is already visible in the UI, you can still navigate to the page and add License A again, which will effectively refresh it.&#x20;

[title] Breaking changes
[path] SDKs/Go SDK/v2/

## **LicenseClient Updates**

In SDK v1, `LicenseClient` was the primary interface through which client applications interacted with the SDK. It also handled responsibilities like saving the license file to storage. For example, methods like `LicenseClient.ActivateLicense()` and `LicenseClient.ActivateOffline()` would automatically persist the license data.

In SDK v2, we've introduced new higher-level layers that now wrap around `LicenseClient` and are responsible for tasks like license validation, storage, and management.

### **Offline Licensing Responsibilities Moved**

Offline licensing logic has been **fully removed from LicenseClient**. The following functions have been **deprecated**:

- GenerateOfflineLicenseRequest
- ActivateOffline
- DeactivateOffline

Their logic has been moved to the **LicenseHandler**, which now automatically orchestrates the offline flow. Offline licensing involves **no real-time communication** with the LicenseSpring API. Now, LicenseClient strictly focuses on **online API interaction** only.

**Note:** The v1 version of `ActivateOffline()` had the option to **send the activation request directly** to the API. This is no longer available in v2. Instead:

- Use **airgap** functionality, or
- Use the **new offline flow** that involves generating and transferring a license file.

This update brings the SDK more in line with the **security principles of true offline licensing**.

### **Hardware ID Validation Is Now Enforced**

In v1, the SDK **did not validate** that the hardware ID in the activation request matched the machine actually performing the activation. This allowed users to generate an activation request on one machine and activate it on another — which **undermines the concept of node-locked licenses**. In v2, this has changed:

- The SDK now enforces **hardware ID checks** during license activation.
- If your workflow involves generating requests on one machine and activating on another, you **must explicitly set the hardware ID** of the target machine in the request generator.

### **Summary of Breaking Changes**

| **Feature**               | **SDK v1**                   | **SDK v2**              |
| ------------------------- | ---------------------------- | ----------------------- |
| License file storage      | Handled inside LicenseClient | Moved to LicenseHandler |
| Offline licensing methods | Part of LicenseClient        | Moved to LicenseHandler |
| Hardware ID enforcement   | Not enforced                 | Enforced                |

### **Migration Note**

If you're still directly using LicenseClient in your application:

- You **must update** your code to use LicenseHandler.
- Otherwise, **your license data will no longer be saved or updated**, and you’ll **lose critical logic** like validation, storage, and offline flow handling.

## Hardware ID Generation in SDK v2

SDK v2 introduces a new hardware ID generation module that supports multiple algorithms, allowing for greater flexibility and improved security. However, **none of the new algorithms produce the same hardware ID as SDK v1**.

If maintaining compatibility with the hardware ID from SDK v1 is important for your setup, you can explicitly configure the `LicenseHandler` to use the legacy method. That said, we **strongly recommend migrating to the new module**, as it offers better robustness and security.

To learn how to configure either the new algorithm or retain the old one, refer to the Configuration Guide for detailed setup instructions.

## License File Path

In SDK v2, the **default name and path of the license file have changed** to align with other SDKs. If you already have a license file stored in the **old default location** and you wish to continue using it **without moving it**, you’ll need to **manually provide its path** as a custom license file location during configuration.

## **FloatingClient and ManagementClient Updates**

In v1, support for the `FloatingClient` and `ManagementClient` was built-in. However, **these are not yet available in v2**. They are planned for future releases but **are not part of the initial version**.

**If your project depends on these APIs:**

- **Do not upgrade to v2** at this time.
- Alternatively, remove or isolate that logic until full support is released in a later version.


[title] Floating Server V1
[path] Floating Server/

The Floating Server allows you to leverage LicenseSpring’s licensing features in an on-premise environment. It can operate both online and offline, supporting a variety of licensing models. This makes it ideal for organizations requiring flexible license management, especially in environments with limited internet access or when high control over license distribution is necessary.

## How It Works

The Floating Server facilitates the creation and management of multiple licenses, each with its own configuration. This allows you to tailor licensing to your product’s needs. The server supports various license types, including:

- **Floating License Registrations**: Dynamically allocate licenses across multiple users or devices.
- **License Consumptions**: Track and manage how licenses are consumed across your organization.
- **Feature Registrations**: Control feature-specific access by enabling or disabling certain features.
- **Feature Consumptions**: Monitor feature usage and consumption, enabling granular control over product functionality.

Each license and feature registration can be customized to meet the specific needs of your organization or product offering.

## **Deployment**

The Floating Server can be deployed in various environments to suit your needs. Choose from:

- [**Executable**](docId\:nUigSoDmRuiadQA-MtJe1): Download and run on Windows, macOS, or Linux.
- [**Docker**](docId\:F6_e9q0DteogfAhmR997-):  Use a containerized environment for easy management.
- [**Kubernetes (Helm)**](docId\:Pf5ciOZrNmrcQlXTLaeJD): Orchestrate and scale in a Kubernetes cluster.

For assistance with selecting a deployment type, refer to the [**Deployment Methods**](docId\:nXbg06L5TvR1lsvDMI2Tb) section.

## **Configuration**

Configure the Floating Server using the `config.yaml` file, where you can specify key settings such as the database type, API keys, and product licenses.

For more information on how to configure your server, visit the [**Configuration**](docId\:Ai5mHs20R-RCJ9f8Ey26C) section.

## **API**

The Floating Server offers an HTTP API for managing licenses, registrations, and consumptions programmatically. Configure your API and shared keys in the `config.yaml` file.

For full details on API usage, check the **API Reference** section.

[title] Features
[path] SDKs/Go SDK/v2/Samples/

Licenses in our SDK support **features.** A license can contain multiple features; each with its own behavior and rules. These features can be of different types, such as **floating** or **consumption.**

## Floating Features

In the case of **floating features**, the SDK provides functionality similar to floating licenses. A floating feature allows a client to check out a floating slot for a limited time (the **floating period**), after which the slot expires unless explicitly released earlier.

Both the local license file and the LicenseSpring platform will reflect the current status of floating slots in use.

### Checking Out a Floating Feature

To occupy a floating slot for a feature, use `CheckLicenseFeature`. Once called, the SDK will store the updated slot usage locally, and you can inspect it using `GetFeature(featureCode)` on the license data:

```go
	ld, err = lh.CheckLicenseFeature(ctx, featureCode)
	if err != nil {
		fmt.Println("feature check error: %w", err)
		return err
	}
	feature := ld.GetFeature(featureCode)
	fmt.Printf("Floating slots in use: %d\n", feature.FloatingInUseCount)
```

The `FloatingInUseCount` field indicates how many devices are currently using that feature under this license.

### Releasing a Floating Feature

To release a floating slot before the end of the floating period (for example, when shutting down the application), use the following:

```go
	ld, err = lh.ReleaseFloatingLicenseFeature(ctx, featureCode)
	if err != nil {
		fmt.Println("error releasing floating feature: %w", err)
		return err
	}
	feature = ld.GetFeature(featureCode)
	fmt.Printf("Floating slots in use: %d\n", feature.FloatingInUseCount)
```

Releasing the slot will update both the local license data and the LicenseSpring platform, freeing the slot for other devices.

## Consumption Features

Features of the consumption type allow your application to consume usage limits tied to that feature. These consumptions may be limited or unlimited, depending on how the feature is configured in the LicenseSpring platform.

Similar to consumption licenses, consumption-based features support local usage updates that can later be synced to the cloud.

### Local Consumption Update

To register the consumption of a feature locally (i.e., increase usage before syncing to the cloud), use the `UpdateFeatureConsumption()` method. This updates the `LocalConsumptions` field in your locally stored license file.

```go
	ld, err = lh.UpdateFeatureConsumption(featureCode, 1, true)
	if err != nil {
		return err
	}

	feature := ld.GetFeature(featureCode)
	t := feature.TotalConsumptions
	l := feature.LocalConsumptions
	fmt.Printf("Total Consumptions: %d\n  Local Consumptions: %d\n", t, l)
```

The third argument to `UpdateFeatureConsumption()` controls whether the local file should be updated in addition to in-memory data, which is what we recommend.

### Sync with LicenseSpring Server

To commit the locally recorded consumption to the LicenseSpring backend, call `SyncFeatureConsumption()`.

You can provide:

- One or more feature codes to sync specific features.
- No arguments to sync **all** consumption features at once.

```go
	ld, err = lh.SyncFeatureConsumption(ctx, featureCode)
	if err != nil {
		return err
	}
	feature = ld.GetFeature(featureCode)
	t = feature.TotalConsumptions
	l = feature.LocalConsumptions
	fmt.Printf("Total Consumptions: %d\n  Local Consumptions: %d\n", t, l)
```

After syncing:

- `TotalConsumptions` will reflect the updated count on the LicenseSpring platform.
- `LocalConsumptions` will be reset to 0.


[title] Go SDK V2
[path] SDKs/Go SDK/v2/

## License Manager

The LicenseManager is the core module responsible for managing licenses, communicating with the LicenseSpring server, and handling authentication.

### Struct Definition

:::BlockQuote
type LicenseManager struct \{
&#x20;   LicenseClient license\_client.LicenseClient
&#x20;   LicenseData   \*types.LicenseData
&#x20;   types.OfflineActivationGuard
}
:::

### Constructor Functions

To create a new license manager, use:

:::BlockQuote
NewLicenseManager(apiKey, sharedKey, productCode string, authData auth.Auth, opts ...ConfigurationOption) (\*LicenseManager, error)
:::

For OAuth-based configurations, use:

:::BlockQuote
NewLicenseManagerOAuth(clientId, clientSecret, cryptoKey, productCode string, authData auth.Auth, opts ...ConfigurationOption) (\*LicenseManager, error)
:::

## License Client Configuration

The LicenseManager includes a LicenseClient, which contains all configuration for interacting with the server:

:::BlockQuote
type LicenseClient struct \{
&#x20;   c \*client.Client
&#x20;   LicenseClientConfiguration
}
:::

## Storage

Storage is responsible for securely persisting license-related data such as license files, guard files, and encrypted custom data.

## License Handler

The LicenseHandler is the user-facing layer that wraps the LicenseManager and Storage. It acts as a coordinator:

- Calls the license manager to perform actions (e.g. activation)
- Persists the resulting data to storage (e.g. license file)
- Manages offline guard file storage
- Decouples core logic (license manager) from the storage mechanism

### Example: License Activation Flow

```go
func (lh *LicenseHandler) ActivateLicense(ctx context.Context) error {
    dl, err := lh.LicenseManager.ActivateLicense(ctx)
    if err != nil {
        return err
    }
    err = lh.Storage.SaveLicense(dl)
    if err != nil {
        return errors.LicenseDataStorageFailed()
    }
    return nil
}
```

## Note on Extensibility

The LicenseManager is completely decoupled from the storage implementation. This allows the replacement of the storage layer without changing the license logic.

For example, when floating server support is added in the future:

- We can implement a new Storage logic
- Use the existing LicenseManager as-is
- Replace LicenseHandler with a FloatingServerHandler or similar

More details about license handler in next section.

[title] Generate Offline License
[path] Floating Server/Floating Server V1/User Interface/UI Configuration/

LicenseSpring customers are able to use LicenseSpring's offline license feature with floating server as well.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/pTI6gTrtTwHNVheWuKHdw_image.png)

### Activating Offline License

1. Navigate to server's Configuration page and open the "Generate offline license" tab
2. Enter the product code for which you want to generate a license request
3. Enter the License Key **OR&#x20;**&#x75;sername and password, depending on the type of license
4. Click "Generate file" and then "Download file", that is your license request file
5. Go to [**Offline portal,**](https://offline.licensespring.com/) add the license request file from previous step and receive the activated license file
6. Add the new license file to Floating server as explained in our [**Products**](docId\:rsWCrpnQ1XajOtkPdHRHr) section.


[title] Offline
[path] Floating Server/Floating Server V1/License Options/

Offline licensing is critical for environments that lack direct internet connectivity or require secure, manual activation processes. This guide covers the procedures for generating an offline license request and uploading the license file using the Floating Server API.

## Generate Offline License Request&#x20;

### With API

This operation initiates the process to obtain an offline license by generating a license request. For more information about this API endpoint, visit [**Generate offline license request**](docId\:D8L5UE0uKf51XvxBNCyVI).

### With User Interface

A step-by-step guide of how to generate offline license can be found in [**Generate Offline License**](docId\:l7jqMuSTfDjuaHc_Ggxj2).

## Upload Offline License File&#x20;

### With API

Once you have received the offline license file from our offline portal ([**https://offline.licensespring.com/**](https://offline.licensespring.com/)). our [**Upload offline license file**](docId\:ENnWubTfi2p2y6sYgqv0A)  is used to upload the file to activate the license.

### With User Interface

The offline license file can be uploaded to the Floating Server, as seen under the [**offline licenses section in our products documentation**](https://docs.licensespring.com/floating-server/ui/configuration/products#lFWPQ).

## How to Refresh Offline Licenses

Refreshing an offline license follows a similar process as online licenses, but with an additional step. First, generate a new license file (refresh file) through the offline licensing platform. More information on license refresh files can be found in [**our guide for offline licensing**](https://docs.licensespring.com/sdks/tutorials/licensing-scenarios/offline#NpIPB).

Once the refresh file is ready, you can upload it to the Floating Server as you would with a normal license file. This process updates the license while maintaining offline functionality.&#x20;

[title] config
[path] Floating Server/Floating Server V1/API Reference/


[title] SDK Licensing
[path] SDKs/node.js SDK/

## SDK License

:::BlockQuote
LicenseSpring SDK Source Code License (LSSCL)

Preamble:
This LicenseSpring SDK Source Code License (LSSCL) governs the use, distribution, and modification of the source code for this LicenseSpring SDKs. This SDK is designed to facilitate the integration of LicenseSpring's license management service into your applications. By accessing, using, or modifying the SDK, you agree to the terms and conditions set forth in this license.

1\. Permissions:

&#x9;\* You are permitted to access, read, and modify the source code of this LicenseSpring SDK.
&#x9;\* You may create derivative works that include this SDK, provided all derivative works are used solely as part of the LicenseSpring service.

2\. Distribution:

&#x9;\* You may distribute the original or modified versions of software that incorporates the SDK, provided that all distributed versions retain this LSSCL license.
&#x9;\* Distributed versions, including modifications, must be used to facilitate the integration of LicenseSpring’s service and may not be:
&#x9;	\* Provided as part of a hosted or cloud-based service that allows others to access the SDK’s functionality without interacting directly with the LicenseSpring service.
&#x9;	\* Integrated into other services which compete with or do not use the LicenseSpring service.

3\. Usage Restrictions:

&#x9;\* The SDK, in its original or modified form, may only be used as part of the LicenseSpring service, whether on a free or paid plan.
&#x9;\* You are prohibited from using the SDK independently or as part of any service that does not interact with the LicenseSpring service.

4\. Prohibited Actions:

&#x9;\* You may not circumvent or disable any technical measures that control access to the SDK.
&#x9;\* You must not remove, alter, or obscure any license notices, copyright notices, or other proprietary notices from the SDK.

5\. Termination:

&#x9;\* Any violation of these terms will result in the automatic termination of your rights under this license.
&#x9;\* Upon termination, you must cease all use and distribution of the SDK and destroy all copies in your possession.

6\. Disclaimer of Warranty and Liability:

&#x9;THE SOFTWARE IS PROVIDED "AS IS" AND LICENSESPRING DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. LICENSESPRING SHALL NOT BE LIABLE FOR ANY DAMAGES ARISING OUT OF OR RELATED TO THE USE OR PERFORMANCE OF THE SOFTWARE.

Copyright 2024 Cense Data Inc DBA LicenseSpring
Contact: support\@licensespring.com
:::

## Bundled Dependencies

LicenseSpring node.js SDK contains the following 3rd-party libraries bundled as dependencies:

| Dependency        | Version | License                                                                                                                                      |
| ----------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| axios             | 1.7.7   | [**https://github.com/axios/axios/blob/HEAD/LICENSE**](https://github.com/axios/axios/blob/HEAD/LICENSE)                                     |
| dayjs             | 1.11.13 | [**https://github.com/iamkun/dayjs/blob/HEAD/LICENSE**](https://github.com/iamkun/dayjs/blob/HEAD/LICENSE)                                   |
| dotenv            | 16.4.5  | [**https://github.com/motdotla/dotenv/blob/master/LICENSE**](https://github.com/motdotla/dotenv/blob/master/LICENSE)                         |
| dotenv-run-script | 0.4.1   | [**https://github.com/kraenhansen/dotenv-run-script/blob/main/LICENSE**](https://github.com/kraenhansen/dotenv-run-script/blob/main/LICENSE) |
| elliptic          | 6.6.1   | [**https://github.com/indutny/elliptic**](https://github.com/indutny/elliptic)                                                               |
| hash.js           | 1.1.7   | [**https://github.com/indutny/hash.js**](https://github.com/indutny/hash.js)                                                                 |
| koffi             | 2.9.1   | [**https://github.com/Koromix/koffi/blob/master/LICENSE.txt**](https://github.com/Koromix/koffi/blob/master/LICENSE.txt)                     |
| typia             | 6.11.1  | [**https://github.com/samchon/typia/blob/master/LICENSE**](https://github.com/samchon/typia/blob/master/LICENSE)                             |
| unzipper          | 0.12.3  | [**https://github.com/ZJONSSON/node-unzipper/blob/master/LICENSE**](https://github.com/ZJONSSON/node-unzipper/blob/master/LICENSE)           |


[title] Hardware Key
[path] Floating Server/Floating Server V1/License Options/

In the floating server, when the hardware key is plugged in and a license-requiring hardware key is added to the floating server, the server's hardware ID changes to the serial number of the hardware key. From then on, every other action in this server uses the new hardware ID, as long as the hardware key is connected to the server. Multiple licenses can be activated using the same hardware key.&#x20;

:::hint{type="danger"}
To successfully run the floating server with the hardware dongle, make sure that no other process is using smart card readers, as this will result in an error in the floating server.

More details on how to detect those services can be found at the end of this page.
:::

## Activate a hardware-key-requiring license

The following steps are required to activate a hardware-key-requiring license in the floating server:

- **1. Create a Hardware-Key-Requiring License&#x20;**
  - Follow the instructions on our [**Hardware Key Licensing**](docId\:tWAsrTiNMFw7Pb0qEWr6a) page to create a new license that requires hardware keys.
- **2. Start the Floating Server&#x20;**
  - Launch the Floating Server and navigate to the configuration page.&#x20;
- **3. Select the Authentication Method**
  - From the dropdown menu on the configuration page, select the method of license authentication:
    - **Key Auth**
    - **User Auth**
  - Ensure that the checkbox for hardware key licenses is selected when adding a license that requires a hardware key.



![Configuration page of the floating server](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/PU-ZTH-EZf8OKMVRc_VD2_image.png "Configuration page of the floating server")

- **4. Plug in the Hardware Key**
  - Ensure that a hardware key, which has been provisioned using the LicenseSpring platform, is plugged into the server.
- **5. Add the License**
  - Add the product that requires the hardware key (e.g., "hwbased") to the Floating Server. The server will recognize that the hardware key is connected.

  - ![Hardware Key Box](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/URyeBo821L3v0GTrBtmsn_image.png "Hardware Key Box")
- **6. Confirm License Activation**
  - After adding the product, the license will be successfully activated on the Floating Server. The hardware ID of the server will now change to the serial number of the hardware key, as long as the hardware key remains connected.
- **7. Observe the Hardware ID Change**
  - The hardware ID of the Floating Server will continue to use the hardware key’s serial number for all actions as long as the key is connected. If the hardware key is disconnected, the hardware ID will revert to its original value.
- **8. View Activation in LicenseSpring**
  - In the LicenseSpring platform, the license activation will be visible, showing that the hardware key’s serial number is being used as the hardware ID.

![The Hardware ID shown in the platform is the serial number of the hardware key.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/eH3PnQJosqpeH6xbJixUL_image.png "The Hardware ID shown in the platform is the serial number of the hardware key.")

- **9. Add Additional Licenses**
  - Additional licenses, whether they require hardware keys or not, can also be added to the Floating Server. This includes both user-based and license-key authentication methods.

Once a hardware-key-based license is added to the server, any subsequent actions involving that license will first verify the hardware key's validity. The action will fail , if the key is invalid (e.g., disconnected).

### Invalid Hardware Key Handling

To address scenarios with missing or invalid hardware keys, we provide two solutions:

1. **Default Behavior**:
   When a hardware key is missing or invalid, the server returns an error.
2. **Crash on Missing Hardware Key**:
   If the `crashIfNoHardwareKey` flag is set to true during server setup, the server will crash when an invalid or missing hardware key is accessed.

This feature was introduced in version v1.6.0 and was implemented to accommodate specific use cases, such as managing hardware keys in high-availability setups.

## Usage examples

Using the API to log in as an admin, add consumptions, feature consumptions, register a user, and register a user to a feature of a license that requires hardware key verification. This example takes advantage of authentication mode to enforce role-based access control. If you are using the server without authentication mode, you can omit the authorization headers.

### **Use user/pass to login**

```curl
curl -u 'user1':'pass1' http://localhost:8080/auth -H "Accept: application/json"
```

Response:

`{"message":"Login successful","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjY4NTU4OTMsImlhdCI6MTcyNjc2OTQ5Mywicm9sZSI6ImFkbWluIiwidXNlcm5hbWUiOiJ1c2VyMSJ9.fhJefnu7X7iECS3Brf36PVdqHRLeZIuwONTfkHdJnjA"}`

### **Add the product&#x20;**

`using the "isHWKeyReq" parameter`

```curl
curl -X GET "http://localhost:8080/api/v4/addProduct?product=hwbased&licenseKey=WTUS-5HHH-V8YP-WUHW&isHWKeyReq=yes" -H "Authorization: Bearer {token_here}" -H "Accept: application/json" -H "Content-Type: application/json" -d '{}'
```

### Add consumptions

```curl
curl -X POST "http://localhost:8080/api/v4/add_consumption" -H "Authorization: Bearer {token_here}" -H "Accept: application/json" -H "Content-Type: application/json" -d '{"product":"hwbased", "consumptions": 2}'
```

### **Add feature consumptions**

```curl
curl -X POST "http://localhost:8080/api/v4/add_feature_consumption" -H "Authorization: Bearer {token_here}" -H "Accept: application/json" -H "Content-Type: application/json" -d '{"product":"hwbased", "feature": "consFeature2", "consumptions": 2}'
```

### **Register User**

```curl
curl -X POST "http://localhost:8080/api/v4/register" -H "Authorization: Bearer {token_here}" -H "Accept: application/json" -H "Content-Type: application/json" -d '{
  "product": "hwbased",
  "user": "user1",
  "os_hostname": "",
  "ip_local": "0.1.1.1",
  "user_info": "",
  "registered_at": "2024-08-26T12:21:59.776731-07:00",
  "borrowed_until": "0001-01-01T00:00:00Z"
}'
```

If no errors occur, the license object will be returned.

### **Register User to Feature**

```curl
curl -X POST "http://localhost:8080/api/v4/featureRegister" -H "Authorization: Bearer {token_here}" -H "Accept: application/json" -H "Content-Type: application/json" -d '{
  "product": "hwbased", "feature": "consFeature2",
  "user": "user2",
  "os_hostname": "",
  "ip_local": "0.1.1.1",
  "user_info": "",
  "registered_at": "2024-08-26T12:21:59.776731-07:00",
  "borrowed_until": "0001-01-01T00:00:00Z"
}'
```

Response:
`{"product":"hwbased","feature":"consFeature2","user":"user2","os_hostname":"","ip_local":"0.1.1.1","user_info":"","registered_at":"2024-09-19T12:39:16.356495803-07:00","borrowed_until":"0001-01-01T00:00:00Z"}`

### **Unplug the hardware key or restart the server, then add consumption**

```curl
curl -X POST "http://localhost:8080/api/v4/add_feature_consumption" -H "Authorization: Bearer {token_here}" -H "Accept: application/json" -H "Content-Type: application/json" -d '{"product":"hwbased", "feature": "consFeature2", "consumptions": 2}'
```

Response:
`{"code":"hardware_key_not_accessible","message":"No available valid hardware key to perform the action: adding feature consumption","status":400}`

## Detect processes using smart card reader

To find which processes are using a smart card reader on your machine, you can use the following methods depending on your operating system:

**On Linux:**

- **Use&#x20;**`lsof`:
  The `lsof` command lists open files and the processes that have opened them. Since smart card readers are typically handled as devices, you can find processes interacting with them.

1. First, find the device file for your smart card reader. This is usually in `/dev` and might be something like `/dev/pcsc`, `/dev/ttyUSB0`, or similar.
2. Run the following command to check which processes are accessing the device:

```curl
lsof /dev/<device-name>
```

Example:

```curl
lsof /dev/ttyUSB0
```

- **Check PC/SC Daemon**:
  If you’re using a PC/SC compliant smart card reader, the `pcscd` service manages the communication. You can check if `pcscd` is running, and find its process ID:

```curl
ps aux | grep pcscd
```

- **Use&#x20;**`fuser`:
  The `fuser` command shows which processes are accessing a specific file or device:

```curl
fuser /dev/<device-name>
```

**On Windows:**

- **Use Task Manager**:
  Open the Task Manager (Ctrl + Shift + Esc), and look for applications or services related to smart card access, like "Smart Card Service" or "SCardSvr". These may interact with the smart card reader.
- **Use&#x20;**`sc query`:
  You can also use the command prompt to query the status of the Smart Card service:

```curl
sc query SCardSvr
```

- **Sysinternals Tools**:
  The [**Sysinternals Process Explorer**](https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer) allows you to see what files, directories, and handles processes are using. Open Process Explorer and search for processes accessing smart card-related files or drivers.

**On macOS:**

- **Use&#x20;**`lsof`:
  Similar to Linux, you can use `lsof` to find processes using the smart card reader:

```curl
lsof | grep smartcard
```

- **Check the Smart Card Daemon**:
  On macOS, the `pcsctest` command can interact with the smart card reader and might provide information about active processes:

```curl
pcsctest
```

These methods should help you identify which processes are interacting with your smart card reader.


[title] Get license
[path] Floating Server/Floating Server V1/API Reference/license/

{
  "id": "dYPaT7EH6jpB4KwvrUbu0",
  "data": {
    "url": "http://localhost:8080/api/v4/license",
    "name": "Get license",
    "method": "GET",
    "request": {
      "pathParameters": [],
      "queryParameters": [
        {
          "kind": "optional",
          "name": "product",
          "type": "string"
        }
      ],
      "headerParameters": [],
      "bodyDataParameters": [],
      "formDataParameters": []
    },
    "responses": [
      {
        "statusCode": "200",
        "description": "",
        "jsonExample": ""
      }
    ],
    "contentType": "application/json"
  },
  "type": "api-oas-v2",
  "children": [
    {
      "text": ""
    }
  ]
}
[title] Best Practices
[path] Floating Server/Floating Server V1/

The Best Practices section provides guidelines and recommendations for optimizing the use of the Floating Server. By following these practices, you can enhance [**Security**](docId\:uPNYPY46BTK8iP3FWr5gF), properly utilize [**Floating Features**](docId\:fcSUKwoO8k2E5oNfqFtRo), perform [**Whitelabeling**](docId:1b4p9u0wS5m1JxXGqkTKc) , and learn how to [**Removing a License**](docId\:yIUPiDY7WBQhsD-iWE7Dm) from the server. Whether you're deploying the server, managing configurations, or securing your environment, these best practices will help you get the most out of your Floating Server setup.&#x20;

[title] Management Client
[path] SDKs/Go SDK/v1 (legacy)/

:::hint{type="info"}
LicenseSpring’s new [**Go SDK V2**](docId\:rDJT5fZ-ZkOsGHD5Jso9c)  is now available! This version is a complete rewrite with breaking changes and will receive all future updates and support.

The legacy Go SDK (v1) is deprecated and maintained for backward compatibility only. New users should use v2.
:::

:::BlockQuote
**Note:** Read [**Common**](docId\:u_qOx_n0BARrlS2ujjS1_) before this.
:::

### Importing the Management Client

```go
import(
  "gitlab.com/l3178/sdk-go/management_client"
  management_request "gitlab.com/l3178/sdk-go/management_client/models/request"
)
```

### Creating the Client

```go
config := management_client.NewManagementClientConfiguration("managementKey")
c := management_client.NewManagementClient(config)
```

### Customer API

```go
ctx := context.Background()

t.Run("Create", func(t *testing.T) {
	resp := c.CustomerApi().CreateCustomer(ctx, management_request.CreateCustomerRequest{
		Email:     "ttt@ttt.ttt",
		FirstName: "Test",
	})
	require.NoError(t, resp.Error)
	id = resp.Value.Id
})

t.Run("List", func(t *testing.T) {
	resp := c.CustomerApi().ListCustomers(ctx, management_request.SearchCustomersRequest{
		Email: "ttt@ttt.ttt",
	})
	assert.NoError(t, resp.Error)
	assert.Equal(t, 1, resp.Count)
})

t.Run("Edit", func(t *testing.T) {
	resp := c.CustomerApi().EditCustomer(ctx, id, management_request.CreateCustomerRequest{
		LastName: "abcd",
	})
	assert.NoError(t, resp.Error)
})

t.Run("Get", func(t *testing.T) {
	resp := c.CustomerApi().ShowCustomer(ctx, id)
	assert.NoError(t, resp.Error)
	assert.Equal(t, "abcd", resp.Value.LastName)
})

t.Run("Delete", func(t *testing.T) {
	err := c.CustomerApi().DeleteCustomer(ctx, id)
	assert.NoError(t, err)
})

t.Run("Create", func(t *testing.T) {
	resp := c.CustomerApi().CreateCustomerLabel(ctx, management_request.CreateCustomerLabelRequest{
		Label: "abcd",
		Color: "efgh",
	})
	require.NoError(t, resp.Error)
	id = resp.Value.Id
})

t.Run("List", func(t *testing.T) {
	resp := c.CustomerApi().ListCustomerLabels(ctx, management_request.SearchRequest{})
	assert.NoError(t, resp.Error)
	assert.Equal(t, 1, resp.Count)
})

t.Run("Edit", func(t *testing.T) {
	resp := c.CustomerApi().EditCustomerLabel(ctx, id, management_request.CreateCustomerLabelRequest{
		Color: "1234",
	})
	assert.NoError(t, resp.Error)
})

t.Run("Get", func(t *testing.T) {
	resp := c.CustomerApi().ShowCustomerLabel(ctx, id)
	assert.NoError(t, resp.Error)
	assert.Equal(t, "1234", resp.Value.Color)
})

t.Run("Delete", func(t *testing.T) {
	err := c.CustomerApi().DeleteCustomerLabel(ctx, id)
	assert.NoError(t, err)
})

t.Run("Create", func(t *testing.T) {
	resp := c.CustomerApi().CreateCustomerAccount(ctx, management_request.CreateCustomerAccountRequest{
		Code: "abcd",
		Name: "efgh",
	})
	require.NoError(t, resp.Error)
	id = resp.Value.Id
})

t.Run("List", func(t *testing.T) {
	resp := c.CustomerApi().ListCustomerAccounts(ctx, management_request.SearchRequest{})
	assert.NoError(t, resp.Error)
	assert.Equal(t, 1, resp.Count)
})

t.Run("Edit", func(t *testing.T) {
	resp := c.CustomerApi().EditCustomerAccount(ctx, id, management_request.CreateCustomerAccountRequest{
		Description: "test",
	})
	assert.NoError(t, resp.Error)
})

t.Run("Get", func(t *testing.T) {
	resp := c.CustomerApi().ShowCustomerAccount(ctx, id)
	assert.NoError(t, resp.Error)
	assert.Equal(t, "test", resp.Value.Description)
})

t.Run("Delete", func(t *testing.T) {
	err := c.CustomerApi().DeleteCustomerAccount(ctx, id)
	assert.NoError(t, err)
})
```

### Device API

```go
ctx := context.Background()

t.Run("SearchDevices", func(t *testing.T) {
	resp := c.DeviceApi().ListDevices(ctx, management_request.SearchDevicesRequest{
		License: testLicenseID,
	})
	assert.NoError(t, resp.Error)
})

t.Run("ShowDevice", func(t *testing.T) {
	c.DeviceApi().ShowDevice(ctx, deviceID)
})

t.Run("ResetDevice", func(t *testing.T) {
	c.DeviceApi().ResetDevice(ctx, deviceID)
})

t.Run("BlacklistDevice", func(t *testing.T) {
	c.DeviceApi().BlacklistDevice(ctx, deviceID)
})

t.Run("CreateDeviceVariable", func(t *testing.T) {
	resp := c.DeviceApi().CreateDeviceVariable(ctx, management_request.CreateDeviceVariableRequest{
		Variable: "test",
		Value:    "value",
		Device:   deviceID,
	})
	assert.NoError(t, resp.Error)
})

t.Run("UpdateDeviceVariable", func(t *testing.T) {
	resp := c.DeviceApi().UpdateDeviceVariable(ctx, deviceID, management_request.UpdateDeviceVariableRequest{
		Variable: "test",
		Value:    "value",
	})
	assert.NoError(t, resp.Error)
})

t.Run("DeleteDeviceVariable", func(t *testing.T) {
	err := c.DeviceApi().DeleteDeviceVariable(ctx, deviceID)
	assert.NoError(t, err)
})

t.Run("SearchDeviceVariable", func(t *testing.T) {
	resp := c.DeviceApi().ListDeviceVariables(ctx, management_request.SearchDeviceVariablesRequest{
		Device: deviceID,
	})
	assert.NoError(t, resp.Error)
})

t.Run("ShowDeviceVariable", func(t *testing.T) {
	resp := c.DeviceApi().ShowDeviceVariable(ctx, deviceID)
	assert.NoError(t, resp.Error)
})
```

### License API

```go
ctx := context.Background()

t.Run("Disable", func(t *testing.T) {
	resp := c.LicenseApi().DisableLicense(ctx, testLicenseID)
	assert.NoError(t, resp.Error)
})

t.Run("Get", func(t *testing.T) {
	resp := c.LicenseApi().GetLicense(ctx, testLicenseID)
	assert.NoError(t, resp.Error)
	assert.False(t, resp.Value.Enabled)
})

t.Run("Enable", func(t *testing.T) {
	resp := c.LicenseApi().EnableLicense(ctx, testLicenseID)
	assert.NoError(t, resp.Error)
})

t.Run("Update", func(t *testing.T) {
	resp := c.LicenseApi().UpdateLicense(ctx, testLicenseID, management_request.UpdateLicenseRequest{
		MaxActivations: 5,
	})
	assert.NoError(t, resp.Error)
})

t.Run("List", func(t *testing.T) {
	resp := c.LicenseApi().SearchLicenses(ctx, management_request.SearchLicensesRequest{})
	assert.NoError(t, resp.Error)
	assert.Equal(t, 3, resp.Count)
})

t.Run("Assign", func(t *testing.T) {
	resp := c.LicenseApi().AssignUser(ctx, testUserLicenseID, management_request.AssignUserToLicenseRequest{
		Email:    "test@abcd.efgh",
		Password: "abcdefgh",
	})
	assert.NoError(t, resp.Error)
})

t.Run("List", func(t *testing.T) {
	resp := c.LicenseApi().ListLicenseUsers(ctx, management_request.SearchUsersRequest{
		EmailContains: "test@abcd.efgh",
	})
	assert.NoError(t, resp.Error)
	require.Equal(t, 1, resp.Count)
	userID = resp.Results[0].Id
})

t.Run("Password", func(t *testing.T) {
	resp := c.LicenseApi().SetUserPassword(ctx, userID, management_request.SetPasswordRequest{
		Password: "test",
	})
	assert.NoError(t, resp.Error)
})

t.Run("Unassign", func(t *testing.T) {
	resp := c.LicenseApi().UnassignUser(ctx, testUserLicenseID, management_request.UnassignRequest{
		LicenseUserId: userID,
	})
	assert.NoError(t, resp.Error)
})

t.Run("List", func(t *testing.T) {
	resp := c.LicenseApi().SearchLicenseCustomFields(ctx, management_request.SearchLicenseCustomFieldsRequest{
		License: testLicenseID,
	})
	require.NoError(t, resp.Error)
	require.Equal(t, 1, resp.Count)
	id = resp.Results[0].Id
})

t.Run("Get", func(t *testing.T) {
	resp := c.LicenseApi().GetLicenseCustomField(ctx, id)
	assert.NoError(t, resp.Error)
})

t.Run("Update", func(t *testing.T) {
	resp := c.LicenseApi().UpdateLicenseCustomField(ctx, id, management_request.UpdateCustomLicenseFieldRequest{
		Value: "test",
	})
	assert.NoError(t, resp.Error)
})
```

### Order API

```go
ctx := context.Background()

t.Run("SearchOrders", func(t *testing.T) {
	resp := c.OrderApi().SearchOrders(ctx, management_request.SearchOrdersRequest{})
	assert.NoError(t, resp.Error)
})

t.Run("GetOrder", func(t *testing.T) {
	resp := c.OrderApi().GetOrder(ctx, orderID)
	assert.NoError(t, resp.Error)
})

t.Run("CreateOrder", func(t *testing.T) {
	resp := c.OrderApi().CreateOrder(ctx, management_models.WebhookOrder{
		Items: []management_models.OrderItem{
			{
				ProductCode: "code",
				Licenses: []management_models.OrderLicense{
					{
						Key: "key",
					},
				},
			},
		},
	})
	assert.NoError(t, resp.Error)
})

t.Run("ExportToCSV", func(t *testing.T) {
	timeStart := time.Now().Add(-5 * time.Hour)
	timeEnd := time.Now()
	resp := c.OrderApi().ExportToCsv(ctx, timeStart, timeEnd)
	assert.NoError(t, resp.Error)
})

t.Run("ExportToCSVRange", func(t *testing.T) {
	var r management_models.Range
	r = r.Last30()
	resp := c.OrderApi().ExportToCsvRange(ctx, r)
	assert.NoError(t, resp.Error)
})

t.Run("GenerateLicenseKeys", func(t *testing.T) {
	resp := c.OrderApi().GenerateLicenseKeys(ctx, management_request.GenerateLicenseRequest{
		Product:  "product",
		Quantity: 1,
	})
	assert.NoError(t, resp.Error)
})

t.Run("AddManagerToOrder", func(t *testing.T) {
	resp := c.OrderApi().AddManagerToOrder(ctx, orderID, management_request.AddManagerToOrderRequest{
		Email:    "email",
		Password: "password",
	})
	assert.NoError(t, resp.Error)
})
```

### Product API

```go
ctx := context.Background()

t.Run("List", func(t *testing.T) {
	resp := c.ProductApi().ListProducts(ctx, management_request.SearchProductsRequest{})
	assert.NoError(t, resp.Error)
	assert.Equal(t, 2, resp.Count)
})

t.Run("Show", func(t *testing.T) {
	resp := c.ProductApi().ShowProduct(ctx, testProductID)
	assert.NoError(t, resp.Error)
})

t.Run("Create", func(t *testing.T) {
	resp := c.ProductApi().CreateInstallationFile(ctx, management_request.CreateInstallationFileRequest{
		FullLink: "link",
		Product:  testProductID,
		Version:  "v1",
	})
	assert.NoError(t, resp.Error)
	id = resp.Value.Id
})

t.Run("List", func(t *testing.T) {
	resp2 := c.ProductApi().ListInstallationFiles(ctx, management_request.SearchInstallationFilesRequest{
		Product: testProductID,
	})
	assert.NoError(t, resp2.Error)
})

t.Run("Show", func(t *testing.T) {
	resp3 := c.ProductApi().ShowInstallationFile(ctx, id)
	assert.NoError(t, resp3.Error)
})

t.Run("Create", func(t *testing.T) {
	resp := c.ProductApi().CreateProductCustomField(ctx, management_request.CreateProductCustomFieldRequest{
		Name:         "field",
		DefaultValue: "test",
		Product:      testProductID,
	})
	assert.NoError(t, resp.Error)
	id = resp.Value.Id
})

t.Run("Show1", func(t *testing.T) {
	respShow := c.ProductApi().ShowProductCustomField(ctx, id)
	assert.NoError(t, respShow.Error)
	assert.Equal(t, "test", respShow.Value.DefaultValue)
})

t.Run("Update", func(t *testing.T) {
	respUpdate := c.ProductApi().UpdateProductCustomField(ctx, id, management_request.UpdateProductCustomFieldRequest{
		Name:         "field",
		DefaultValue: "abcd",
	})
	assert.NoError(t, respUpdate.Error)
})

t.Run("Show2", func(t *testing.T) {
	respShow := c.ProductApi().ShowProductCustomField(ctx, id)
	assert.NoError(t, respShow.Error)
	assert.Equal(t, "abcd", respShow.Value.DefaultValue)
})

t.Run("Delete", func(t *testing.T) {
	err := c.ProductApi().DeleteProductCustomField(ctx, id)
	assert.NoError(t, err)
})

t.Run("List", func(t *testing.T) {
	respList := c.ProductApi().ListProductCustomFields(ctx, management_request.SearchProductCustomFieldsRequest{
		Product: testProductID,
	})
	assert.NoError(t, respList.Error)
	assert.Equal(t, 1, respList.Count)
})
```


[title] LicenseManager
[path] SDKs/Android SDK/

After completing [**SDK Initialization**](docId\:MZbR0pEzZqzPoz2lkGITA), there are a number of methods and objects available to the app developer.

## getCurrent()

In case no active license is available the property value will be null.

```java
License currentLicense = licenseManager.getCurrent();
```

## getTrialLicense(String email)

You can generate a trial key directly from the app using the SDK, which will automatically associate this license key with the provided email. You can later use this data from the LicenseSpring platform to send out email campaigns targeting trial users for example.

:::hint{type="danger"}
After you generate a trial key - the `UnactivatedTrialLicense` object will be returned, you still need to activate it using a call to `licenseManager.activateLicense()`
:::

```java
try {
  UnactivatedTrialLicense trial = licenseManager.getTrialLicense("someemail@gmail.com");
  License license = licenseManager.activateLicense(trial.createIdentity());
}
catch(LicenseSpringException e)
{
  log.error("Something went wrong",e);
  return;
}
```

## activateLicenseKey(ActivationLicense identity)

Attempts to activate the product using provided `ActivationIdentity`. Returns the `License` object that has been activated.

```java
// keybased
ActivationLicense keyBased = ActivationLicense.fromKey("license-key");
License activated = licenseManager.activateLicense(keyBased);

// OR username/pass based - Note that this is the only API which requires the password.
// LicenseSpring will never store user passwords via the SDK.
ActivationLicense userBased = ActivationLicense.fromUsername("username", "password");
License activated = licenseManager.ActivateLicense(userBased);


```

## deactivateLicense(LicenseIdentity identity)

License is deactivated using a method on the Manager. You need to supply the current license identity.

```java
boolean isDeactivated = licenseManager.deactivateLicense(LicenseIdentity.fromKey("sample-key"));

```

## getInstallationFile(LicenseIdentity identity)

Returns the latest valid installation file, if installation files are defined in the LicenseSpring platform. For more details please see [**Product Versioning**](docId\:sz5ImOvmj5QJaWhELsOXt)

```java
InstallationFile installationFile = licenseManager.getInstallationFile(LicenseIdentity.fromKey("sample-key"));

```

## getVersions(LicenseIdentity identity)

Returns all available versions of the product app that are specified in LicenseSpring platform. For more details please see [**Product Versioning**](docId\:sz5ImOvmj5QJaWhELsOXt). Version class only contains String version.

## trackVariables(LicenseIdentity identity, Map\<String, String> variables)

Tracks device based variables for end uses. Can use the `Variable builder` as a utility.

```java
// build your own Map
licenseManager.trackVariables(LicenseIdentity.fromKey("sample-key"), new HashMap<>);


// use utility class to add some variables and track them
DeviceVariables deviceVars = DeviceVariables.builder()
                .variable("one", "some value")
                .variable("another_var", "other_value")
                .build();

licenseManager.trackVariables(LicenseIdentity.fromKey("sample-key"), deviceVars.getVariables());

```

## getProduct()

Gets product details from LicenseSpring servers.

```java
Product product = licenseManager.getProductDetails();
log.info(product.getProductName());
log.info(product.getShortCode());
log.info(product.isAllowTrial());
log.info(product.getTrialDays());
log.info(product.getAuthorizationMethod());

```

## getAirGapActivationCode

Gets the activation code use for air gapped license

Needs the `LicenseSpringConfiguration` field: `airGappedPublicKey` to work with Air Gap Licenses

```java
AirGappedActivation activation = licenseManager.getAirGapActivationCode(
	LicenseIdentity.fromKey("sample-key"), "initializationCodeFromPlatform"
);

log.info(activation.getActivationCode());
log.info(activation.getHardwareId());
log.info(activation.getLicenseKey());
```

## activateAirGapResponse

Activates the air gapped license from the license policy file

Needs the `LicenseSpringConfiguration` field: `airGappedPublicKey` to work with `Air Gap Licenses`

```java
License license = licenseManager.activateAirGapResponse(
	LicenseIdentity.fromKey("sample-key"), 
  	"pathToPolicyFile",
    "policyId"
);

log.info(license.getHardwareId());
log.info(license.getIdentity().getLicenseKey());
```

## verifyAirGapConfirmationCode

Verifies the confirmation code for air gapped license

Needs the `LicenseSpringConfiguration` field: `airGappedPublicKey` to work with `Air Gap Licences`

```java
boolean verified = licenseManager.verifyAirGapConfirmationCode(
	LicenseIdentity.fromKey("sample-key"), 
  	"policyIdFromPlatform",
    "confirmationCodeFromPlatform"
);

log.info(verified);
```


[title] Floating License
[path] SDKs/Go SDK/v2/Samples/

## License Check

The `CheckLicense` function is not only used to validate the current license status, but also plays a role in floating licenses.

If the license is of **floating cloud** type, calling `CheckLicense` will automatically assign one floating slot to the current machine, identified by its hardware ID.

```go
	ld, err = lh.CheckLicense(ctx)
	if err != nil {
		return err
	}
```

## Borrow

Floating licenses come with a predefined **floating period**—a time frame in which the license is valid on a given machine. If the license configuration allows, this period can be **borrowed** or **extended** for offline usage.

You can extend the floating period using one of two methods:

### Borrow for a Specific Number of Hours and Days

```go
	ld, err = lh.BorrowHoursAndDays(ctx, 3, 0)
	if err != nil {
		return err
	}
```

### Borrow Until a Specific Time

```go
	t := time.Now().Add(3 * time.Hour).UTC()
	ld, err = lh.Borrow(ctx, &t)
	if err != nil {
		fmt.Println("license borrow error: %w", err)
		return err
	}
```

These functions will only succeed if the license allows borrowing and there are available slots or permissions for the request.

## Release Floating License

If you no longer need the license on the current machine, or want to release a floating slot before the borrow period ends, you can call:

```go
	ld, err = lh.ReleaseFloatingLicense(ctx)
	if err != nil {
		return err
	}
```

This function immediately frees up the slot assigned to the current machine, making it available for others.

[title] Floating Features
[path] Floating Server/Floating Server V1/Best Practices/

## Topics Covered on This Page

- **Floating feature registration** using `/featureRegister` and `/check_license_feature`
- **Floating feature release** using `/featureRelease` and `/feature_release`&#x20;
- **Releasing all floating feature registrations** using `/featureRelease/all` and `/feature_release/all`

## Offline Floating Feature

Starting from release v1.4.11, the floating server now supports offline floating features. This functionality allows customers to add offline floating features to a product and licenses built for that product. These can then be imported into the floating server, enabling the registration and release of users into that feature entirely offline on their premises.&#x20;

To add these features to a product, navigate to the product within the vendor platform, select the "Features" tab, and click on the "Add Product Feature" button. In the popup window, after specifying the feature's name, code, and other details, check the "Offline Floating Feature" checkbox, as shown in the image below.&#x20;



::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/vvWokL6xPVPadp6mSukXN_image.png" signedSrc size="50" width="764" height="835" position="center" caption alt="feature creation"}

The API endpoints associated with floating features are listed below.&#x20;

### Feature Register

Registers a user to a specific feature of a license on the Floating Server. Requires a **username**, along with the **product code** and **feature code**.

:::ApiMethodV2
```json
{
  "name": "Register a user to a floating feature of a product",
  "method": "POST",
  "url": "http://localhost:8080/api/v4/featureRegister",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "imNcKYIrUNSMO7AMxtnCJ",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Content-Type\", \"application/json\");\n\nvar raw = JSON.stringify({\n  \"product\": \"test\",\n  \"feature\": \"testingFeature\",\n  \"user\": \"testUser\",\n  \"os_hostname\": \"\",\n  \"ip_local\": \"0.1.1.1\",\n  \"user_info\": \"\",\n  \"registered_at\": \"2024-08-26T12:21:59.776731-07:00\",\n  \"borrowed_until\": \"0001-01-01T00:00:00Z\"\n});\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"http://localhost:8080/api/v4/featureRegister\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "imLzTCkvNHv9m_g8Y5Mmw",
        "language": "curl",
        "code": "curl -X POST \"http://localhost:8080/api/v4/featureRegister\" \\\n-H \"Accept: application/json\" \\\n-H \"Content-Type: application/json\" \\\n-d '{\n  \"product\": \"test\",\n  \"feature\": \"testingFeature\",\n  \"user\": \"testUser\",\n  \"os_hostname\": \"\",\n  \"ip_local\": \"0.1.1.1\",\n  \"user_info\": \"\",\n  \"registered_at\": \"2024-08-26T12:21:59.776731-07:00\",\n  \"borrowed_until\": \"0001-01-01T00:00:00Z\"\n}'\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "imLzTCkvNHv9m_g8Y5Mmw"
  },
  "results": {
    "languages": [
      {
        "id": "Isr9vDuLtAMBZMA6D0iWf",
        "language": "200",
        "customLabel": "",
        "code": "{\n  \"product\": \"test\",\n  \"feature\": \"testingFeature\",\n  \"user\": \"testUser\",\n  \"os_hostname\": \"\",\n  \"ip_local\": \"0.1.1.1\",\n  \"user_info\": \"\",\n  \"registered_at\": \"2024-08-26T12:21:59.776731-07:00\",\n  \"borrowed_until\": \"0001-01-01T00:00:00Z\"\n}"
      },
      {
        "id": "UNA7x0opUGF2BEwOXXEZb",
        "language": "400",
        "customLabel": "",
        "code": "{\n  \"code\": \"feature_not_found\",\n  \"message\": \"Feature color not found for product test\",\n  \"status\": 400\n}"
      }
    ],
    "selectedLanguageId": "Isr9vDuLtAMBZMA6D0iWf"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "product",
        "kind": "required",
        "type": "String",
        "description": "product code of the target product"
      },
      {
        "name": "feature",
        "kind": "required",
        "type": "string",
        "description": "feature code of the target feature",
        "children": []
      },
      {
        "name": "user",
        "kind": "required",
        "type": "string",
        "description": "name or id of the user to be registered",
        "children": []
      },
      {
        "name": "os_hostname",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "ip_local",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "user_info",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "registered_at",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "borrowed_until",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "register-a-user-to-a-floating-feature-of-a-product",
  "legacyHash": "hc14237GRf5VjcjwaRpqS"
}
```
:::

### Feature Release

Releases a user who has been registered to a specific feature of a license.

:::ApiMethodV2
```json
{
  "name": "Release a registered user from a floating feature of a product",
  "method": "POST",
  "url": "http://localhost:8080/api/v4/featureRelease",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "imNcKYIrUNSMO7AMxtnCJ",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Content-Type\", \"application/json\");\n\nvar raw = JSON.stringify({\n  \"product\": \"test\",\n  \"feature\": \"testingFeature\",\n  \"user\": \"testUser\",\n  \"os_hostname\": \"\",\n  \"ip_local\": \"0.1.1.1\",\n  \"user_info\": \"\",\n  \"registered_at\": \"2024-08-26T12:21:59.776731-07:00\",\n  \"borrowed_until\": \"0001-01-01T00:00:00Z\"\n});\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"http://localhost:8080/api/v4/featureRelease\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "imLzTCkvNHv9m_g8Y5Mmw",
        "language": "curl",
        "code": "curl -X POST \"http://localhost:8080/api/v4/featureRelease\" \\\n-H \"Accept: application/json\" \\\n-H \"Content-Type: application/json\" \\\n-d '{\n  \"product\": \"test\",\n  \"feature\": \"testingFeature\",\n  \"user\": \"testUser\",\n  \"os_hostname\": \"\",\n  \"ip_local\": \"0.1.1.1\",\n  \"user_info\": \"\",\n  \"registered_at\": \"2024-08-26T12:21:59.776731-07:00\",\n  \"borrowed_until\": \"0001-01-01T00:00:00Z\"\n}'\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "imLzTCkvNHv9m_g8Y5Mmw"
  },
  "results": {
    "languages": [
      {
        "id": "Isr9vDuLtAMBZMA6D0iWf",
        "language": "200",
        "customLabel": "",
        "code": "\"feature_released\""
      },
      {
        "id": "UNA7x0opUGF2BEwOXXEZb",
        "language": "400",
        "customLabel": "",
        "code": "{\n  \"code\": \"feature_not_found\",\n  \"message\": \"Feature color not found for product test\",\n  \"status\": 400\n}"
      }
    ],
    "selectedLanguageId": "UNA7x0opUGF2BEwOXXEZb"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "product",
        "kind": "required",
        "type": "String",
        "description": "product code of the target product"
      },
      {
        "name": "feature",
        "kind": "required",
        "type": "string",
        "description": "feature code of the target feature",
        "children": []
      },
      {
        "name": "user",
        "kind": "required",
        "type": "string",
        "description": "name or id of the user to be registered",
        "children": []
      },
      {
        "name": "os_hostname",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "ip_local",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "user_info",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "registered_at",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "borrowed_until",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "release-a-registered-user-from-a-floating-feature",
  "legacyHash": "FrZBywpcra9HNWagM8eCY"
}
```
:::

### Release All

Releases all users registered to all features across all licenses.

:::ApiMethodV2
```json
{
  "name": "Release all floating feature registrations",
  "method": "GET",
  "url": "http://localhost:8080/api/v4/featureRelease/all",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "imNcKYIrUNSMO7AMxtnCJ",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Content-Type\", \"application/json\");\n\nvar raw = JSON.stringify({});\n\nvar requestOptions = {\n   method: 'GET',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"http://localhost:8080/api/v4/featureRelease/all\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "imLzTCkvNHv9m_g8Y5Mmw",
        "language": "curl",
        "code": "curl -X POST \"http://localhost:8080/api/v4/featureRelease/all\" \\\n-H \"Accept: application/json\" \\\n-H \"Content-Type: application/json\" \\\n-d '{}'\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "imLzTCkvNHv9m_g8Y5Mmw"
  },
  "results": {
    "languages": [
      {
        "id": "Isr9vDuLtAMBZMA6D0iWf",
        "language": "200",
        "customLabel": "",
        "code": "\"\""
      }
    ],
    "selectedLanguageId": "Isr9vDuLtAMBZMA6D0iWf"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "release-all-floating-feature-registrations",
  "legacyHash": "AcOyYpcxXElTsHVRPNolP"
}
```
:::

## LicenseSpring-Compatible Floating Endpoints

To align with LicenseSpring’s API, starting from version **v1.6.2**, three new endpoints have been added to support floating feature functionality. These endpoints behave similarly to those mentioned above, but their routes are modeled after LicenseSpring’s API for compatibility.

### Feature Register

`/check_license_feature` and `/featureRegister` provide the same functionality. They register a user to a specific feature of a license on the Floating Server. They require a **username**, along with the **product code** and **feature code**.

:::ApiMethodV2
```json
{
  "name": "Register a user to a floating feature of a product",
  "method": "POST",
  "url": "http://localhost:8080/api/v4/check_license_feature",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "imNcKYIrUNSMO7AMxtnCJ",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Content-Type\", \"application/json\");\n\nvar raw = JSON.stringify({\n  \"product\": \"test\",\n  \"feature\": \"testingFeature\",\n  \"user\": \"testUser\",\n  \"os_hostname\": \"\",\n  \"ip_local\": \"0.1.1.1\",\n  \"user_info\": \"\",\n  \"registered_at\": \"2024-08-26T12:21:59.776731-07:00\",\n  \"borrowed_until\": \"0001-01-01T00:00:00Z\"\n});\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"http://localhost:8080/api/v4/featureRegister\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "imLzTCkvNHv9m_g8Y5Mmw",
        "language": "curl",
        "code": "curl -X POST \"http://localhost:8080/api/v4/check_license_feature\" \\\n-H \"Accept: application/json\" \\\n-H \"Content-Type: application/json\" \\\n-d '{\n  \"product\": \"test\",\n  \"feature\": \"testingFeature\",\n  \"user\": \"testUser\",\n  \"os_hostname\": \"\",\n  \"ip_local\": \"0.1.1.1\",\n  \"user_info\": \"\",\n  \"registered_at\": \"2024-08-26T12:21:59.776731-07:00\",\n  \"borrowed_until\": \"0001-01-01T00:00:00Z\"\n}'\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "imLzTCkvNHv9m_g8Y5Mmw"
  },
  "results": {
    "languages": [
      {
        "id": "Isr9vDuLtAMBZMA6D0iWf",
        "language": "200",
        "customLabel": "",
        "code": "{\n  \"product\": \"test\",\n  \"feature\": \"testingFeature\",\n  \"user\": \"testUser\",\n  \"os_hostname\": \"\",\n  \"ip_local\": \"0.1.1.1\",\n  \"user_info\": \"\",\n  \"registered_at\": \"2024-08-26T12:21:59.776731-07:00\",\n  \"borrowed_until\": \"0001-01-01T00:00:00Z\"\n}"
      },
      {
        "id": "UNA7x0opUGF2BEwOXXEZb",
        "language": "400",
        "customLabel": "",
        "code": "{\n  \"code\": \"feature_not_found\",\n  \"message\": \"Feature color not found for product test\",\n  \"status\": 400\n}"
      }
    ],
    "selectedLanguageId": "Isr9vDuLtAMBZMA6D0iWf"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "product",
        "kind": "required",
        "type": "String",
        "description": "product code of the target product"
      },
      {
        "name": "feature",
        "kind": "required",
        "type": "string",
        "description": "feature code of the target feature",
        "children": []
      },
      {
        "name": "user",
        "kind": "required",
        "type": "string",
        "description": "name or id of the user to be registered",
        "children": []
      },
      {
        "name": "os_hostname",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "ip_local",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "user_info",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "registered_at",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "borrowed_until",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "register-a-user-to-a-floating-feature-of-a-product-1",
  "legacyHash": "__N2_lKfFj0YZeYg4zHiv"
}
```
:::

### Feature Release

`/feature_release` and `/featureRelease` are functionally equivalent. They release a user who has been registered to a specific feature of a license.

:::ApiMethodV2
```json
{
  "name": "Release a registered user from a floating feature of a product",
  "method": "POST",
  "url": "http://localhost:8080/api/v4/feature_release",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "imNcKYIrUNSMO7AMxtnCJ",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Content-Type\", \"application/json\");\n\nvar raw = JSON.stringify({\n  \"product\": \"test\",\n  \"feature\": \"testingFeature\",\n  \"user\": \"testUser\",\n  \"os_hostname\": \"\",\n  \"ip_local\": \"0.1.1.1\",\n  \"user_info\": \"\",\n  \"registered_at\": \"2024-08-26T12:21:59.776731-07:00\",\n  \"borrowed_until\": \"0001-01-01T00:00:00Z\"\n});\n\nvar requestOptions = {\n   method: 'POST',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"http://localhost:8080/api/v4/featureRelease\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "imLzTCkvNHv9m_g8Y5Mmw",
        "language": "curl",
        "code": "curl -X POST \"http://localhost:8080/api/v4/feature_release\" \\\n-H \"Accept: application/json\" \\\n-H \"Content-Type: application/json\" \\\n-d '{\n  \"product\": \"test\",\n  \"feature\": \"testingFeature\",\n  \"user\": \"testUser\",\n  \"os_hostname\": \"\",\n  \"ip_local\": \"0.1.1.1\",\n  \"user_info\": \"\",\n  \"registered_at\": \"2024-08-26T12:21:59.776731-07:00\",\n  \"borrowed_until\": \"0001-01-01T00:00:00Z\"\n}'\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "imLzTCkvNHv9m_g8Y5Mmw"
  },
  "results": {
    "languages": [
      {
        "id": "Isr9vDuLtAMBZMA6D0iWf",
        "language": "200",
        "customLabel": "",
        "code": "\"feature_released\""
      },
      {
        "id": "UNA7x0opUGF2BEwOXXEZb",
        "language": "400",
        "customLabel": "",
        "code": "{\n  \"code\": \"feature_not_found\",\n  \"message\": \"Feature color not found for product test\",\n  \"status\": 400\n}"
      }
    ],
    "selectedLanguageId": "UNA7x0opUGF2BEwOXXEZb"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [
      {
        "name": "product",
        "kind": "required",
        "type": "String",
        "description": "product code of the target product"
      },
      {
        "name": "feature",
        "kind": "required",
        "type": "string",
        "description": "feature code of the target feature",
        "children": []
      },
      {
        "name": "user",
        "kind": "required",
        "type": "string",
        "description": "name or id of the user to be registered",
        "children": []
      },
      {
        "name": "os_hostname",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "ip_local",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "user_info",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "registered_at",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      },
      {
        "name": "borrowed_until",
        "kind": "required",
        "type": "string",
        "description": "",
        "children": []
      }
    ],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "release-a-registered-user-from-a-floating-feature-1",
  "legacyHash": "lu9FvQ7Ik7uB-NTBsThQz"
}
```
:::

### Release All Features

`/feature_release/all` and `/featureRelease/all` perform the same operation. They release all users registered to all features across all licenses.

:::ApiMethodV2
```json
{
  "name": "Release all floating feature registrations",
  "method": "GET",
  "url": "http://localhost:8080/api/v4/feature_release/all",
  "description": "",
  "tab": "examples",
  "examples": {
    "languages": [
      {
        "id": "imNcKYIrUNSMO7AMxtnCJ",
        "language": "javascript",
        "code": "var myHeaders = new Headers();\nmyHeaders.append(\"Accept\", \"application/json\");\nmyHeaders.append(\"Content-Type\", \"application/json\");\n\nvar raw = JSON.stringify({});\n\nvar requestOptions = {\n   method: 'GET',\n   headers: myHeaders,\n   body: raw,\n   redirect: 'follow'\n};\n\nfetch(\"http://localhost:8080/api/v4/featureRelease/all\", requestOptions)\n   .then(response => response.text())\n   .then(result => console.log(result))\n   .catch(error => console.log('error', error));",
        "customLabel": ""
      },
      {
        "id": "imLzTCkvNHv9m_g8Y5Mmw",
        "language": "curl",
        "code": "curl -X POST \"http://localhost:8080/api/v4/feature_release/all\" \\\n-H \"Accept: application/json\" \\\n-H \"Content-Type: application/json\" \\\n-d '{}'\n",
        "customLabel": ""
      }
    ],
    "selectedLanguageId": "imLzTCkvNHv9m_g8Y5Mmw"
  },
  "results": {
    "languages": [
      {
        "id": "Isr9vDuLtAMBZMA6D0iWf",
        "language": "200",
        "customLabel": "",
        "code": "\"\""
      }
    ],
    "selectedLanguageId": "Isr9vDuLtAMBZMA6D0iWf"
  },
  "request": {
    "pathParameters": [],
    "queryParameters": [],
    "headerParameters": [],
    "bodyDataParameters": [],
    "formDataParameters": []
  },
  "currentNewParameter": {
    "label": "Body Parameter",
    "value": "bodyDataParameters"
  },
  "autoGeneratedAnchorSlug": "release-all-floating-feature-registrations-1",
  "legacyHash": "VdYXrXYNyYCfpCtHu57wa"
}
```
:::


[title] How to Run the Sample Files
[path] SDKs/Go SDK/v2/Samples/

Clear and practical samples are provided to demonstrate how to run specific licensing scenarios. You can use these samples as a foundation to build more advanced or customized workflows.

Currently, the samples require a config.yaml file located in the same directory. You must populate it with your credentials — including either OAuth credentials (client ID and client secret) or API/Shared keys — along with product details such as the product code and corresponding license credentials (either a license key or username/password pair).

Please note that most samples are written assuming **key-based licenses** by default, but you can easily adapt them for username/password licenses by updating the configuration.

### Step 1: Fill out config.yaml

Here’s an example structure:

```yaml
clientId: "your-client-id"
clientSecret: "your-client-secret"
cryptoProviderKey: "your-crypto-provider-key" # Required if using OAuth
apiKey: "your-api-key"
sharedKey: "your-shared-key"
verbose: true
verify_signature: true

products:
  productCode1:
    licenseKey: "your-license-key"
  productCode2:
    username: "your-username"
    password: "your-password"
```

- If you are using **OAuth**, make sure to fill in the cryptoProviderKey field.
- If you are using **API/SharedKey** authentication, you can leave the OAuth fields empty.

### Running the Online Activation Sample

To run a sample that **activates**, **checks**, and **deactivates** a license, you can use the provided ExampleOnlineActivation() sample function.

Simply call this function inside your main function and provide it with two parameters:

- useOAuth (bool): Set to true if you are using OAuth authentication, otherwise false.
- productCode (string): The product code of the license you want to activate.

Example:

```go
func main() {
    err := ExampleOnlineActivation(true, "your-product-code")
    if err != nil {
        fmt.Println(err)
    }
}
```

**Important Notes:**

- Ensure you have created a license that supports **online activation**.
- If you are using OAuth, make sure the first parameter (useOAuth) is set to true.
- All required credentials must be correctly set up in your config.yaml file.

### Running the Online Activation with Consumption Sample

The next sample demonstrates how to **activate a license**, **add consumption**, **sync the consumption**, **revert** the license back to its previous state, and then **deactivate** it.
&#x20;You can use the provided ExampleOnlineActivationAddConsumption() function to perform this flow.

To run it, simply call the function inside your main function and pass two parameters:

- useOAuth (bool): Set to true if you are using OAuth authentication, otherwise false.
- productCode (string): The product code for the **online consumption license** you want to test.

```go
func main() {
    err := ExampleOnlineActivationAddConsumption(true, "your-consumption-product-code")
    if err != nil {
        fmt.Println(err)
    }
}
```

**Important Notes:**

- Ensure the license you use is a **consumption-based online license**.
- All required credentials and product information must be correctly configured in your config.yaml.
- If you are using OAuth, remember to pass true for the first parameter.

Similar to the samples explained here, there are **additional sample files&#x20;**&#x61;vailable in the repository. These cover a wide range of scenarios such as **offline activation**, **air-gapped environments**, **floating licenses**, and more. Each sample is provided with **detailed comments** to guide you step-by-step through the process.

[title] Java Exception Handling
[path] SDKs/Android SDK/

In case of errors, LicenseSpring SDK will throw an exception, SDK-specific exceptions will always derive from LicenseSpringException class.

The following exceptions are possible:

- **LicenseSpringException&#x20;**- All SDK Exceptions are wrapped in this exception.
- **LicenseExpiredException&#x20;**- License Expired
- **ConsumptionException&#x20;**- When feature/license consumptions limits have been reached
- **LicenseSpringServerException&#x20;**- Any License server error is wrapped in this exception. See [**docs/errors-and-response-codes&#x20;**](https://app.archbee.com/docs/FbT_Z5Cu33D-LVZx1fRkU/7Xzj4cVQsFtElPC9LDKMt)for detailed messages. The response is wrapped in the ErrorResponse class.



[title] Watch Dogs
[path] SDKs/Python SDK/

## Watch Dogs

:::hint{type="info"}
[**Watchdog**](https://app.archbee.com/docs/FbT_Z5Cu33D-LVZx1fRkU/yaZxsl7FnxbYi883jYc3-#PBfrR) is a thread that regularly checks **license** or **feature**
:::

## License Watch Dogs

### setup\_license\_watch\_dog

Initializes and starts the license watchdog with the specified callback and timeout settings.

Parameters:

- **callback** (callable)\:A callable to be executed by the watchdog in response to specific events or conditions.
- **timeout** (int)**:&#x20;**&#x54;he period in minutes after which the watchdog should perform its checks.
- **deamon&#x20;**(bool, optional): Run thread as deamon. Defaults to False.&#x20;
- **run\_immediately&#x20;**(bool,optional): run license check immediately, if False wait for timeout first. Defaults to True

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.setup_license_watch_dog(callback,timeout)
                                
```

### stop\_license\_watch\_dog

Stops the license watchdog if it is currently running.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.setup_license_watch_dog(callback,timeout)
                                
license.stop_license_watch_dog()
```

## Feature Watch Dogs

### setup\_feature\_watch\_dog

Initializes and starts the feature watchdog with the specified callback and timeout.

Parameters:

- **callback** (callable): A callable to be executed by the watchdog in response to specific events or conditions.
- **timeout** (int)**:&#x20;**&#x54;he period in minutes after which the watchdog should perform its checks.
- **deamon&#x20;**(bool, optional): Run thread as deamon. Defaults to False.&#x20;

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.setup_feature_watch_dog(callback,timeout) 
                                
```

### stop\_feature\_watch\_dog

Stops the feature watchdog if it is currently running.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.setup_feature_watch_dog(callback,timeout) 
                                
license.stop_feature_watch_dog() 
```


[title] Download Android SDK
[path] SDKs/Android SDK/

## LicenseSpring Android SDK Versions

| Version | Release Date        | Download Link                                                                                                                             |
| ------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| v1.5.0  | December 12th, 2023 | [**Download v1.5.0**](https://licensespring-android-sdk.s3.amazonaws.com/com/licensespring/androidsdk/1.5.0/androidsdk-1.5.0-release.aar) |
| v1.4.0  | October 12th, 2023  | [**Download v1.4.0**](https://licensespring-android-sdk.s3.amazonaws.com/com/licensespring/androidsdk/1.4.0/androidsdk-1.4.0-release.aar) |
| v1.3.0  | April 28th, 2023    | [**Download v1.3.0**](https://licensespring-android-sdk.s3.amazonaws.com/com/licensespring/androidsdk/1.3.0/androidsdk-1.3.0-release.aar) |
| v1.2.0  | April 19th, 2023    | [**Download v1.2.0**](https://licensespring-android-sdk.s3.amazonaws.com/com/licensespring/androidsdk/1.2.0/androidsdk-1.2.0-release.aar) |
| v1.1.8  | February 22nd, 2023 | [**Download v1.1.8**](https://licensespring-android-sdk.s3.amazonaws.com/com/licensespring/androidsdk/1.1.8/androidsdk-1.1.8-release.aar) |
| v1.1.7  | January 30th, 2023  | [**Download v1.1.7**](https://licensespring-android-sdk.s3.amazonaws.com/com/licensespring/androidsdk/1.1.7/androidsdk-1.1.7-release.aar) |
| v1.1.6  | January 19th, 2023  | [**Download v1.1.6**](https://licensespring-android-sdk.s3.amazonaws.com/com/licensespring/androidsdk/1.1.6/androidsdk-1.1.6-release.aar) |
| v1.1.5  | January 16th, 2023  | [**Download v1.1.5**](https://licensespring-android-sdk.s3.amazonaws.com/com/licensespring/androidsdk/1.1.5/androidsdk-1.1.5-release.aar) |
| v1.1.4  | January 10th, 2023  | [**Download v1.1.4**](https://licensespring-android-sdk.s3.amazonaws.com/com/licensespring/androidsdk/1.1.4/androidsdk-1.1.4-release.aar) |
| v1.1.3  | November 4th, 2022  | [**Download v1.1.3**](https://licensespring-android-sdk.s3.amazonaws.com/com/licensespring/androidsdk/1.1.3/androidsdk-1.1.3-release.aar) |
| v1.1.2  | August 19th, 2022   | [**Download v1.1.2**](https://licensespring-android-sdk.s3.amazonaws.com/com/licensespring/androidsdk/1.1.2/androidsdk-1.1.2-release.aar) |
| v1.1.1  | August 10th, 2022   | [**Download v1.1.1**](https://licensespring-android-sdk.s3.amazonaws.com/com/licensespring/androidsdk/1.1.1/androidsdk-1.1.1-release.aar) |
| v1.1    | June 14th, 2020     | [**Download v1.1**](https://licensespring-android-sdk.s3.amazonaws.com/com/licensespring/androidsdk/1.1/androidsdk-1.1-release.aar)       |
| v1.0    | May 11th, 2020      | [**Download v1.0**](https://licensespring-android-sdk.s3.amazonaws.com/com/licensespring/androidsdk/1.0/androidsdk-1.0-release.aar)       |


[title] Type Declarations
[path] SDKs/node.js SDK/

The package provides typescript declarations for classes, methods and properties.

## Response Types

```typescript
export type ActivateBundleResponse = ActivateLicenseResponse[];

export type ActivateLicenseResponse = LicenseResponseBase & {
  request: string,
  active: boolean,
  device_id: number,
  validity_period: string | null,
  is_expired: boolean,
  hardware_id: string,
  username?: string,
  max_license_users?: number,
  is_floating_cloud: boolean,
  floating_in_use?: boolean,
  license_signature: string,
  variables?: ({
    value: string;
    device_id: number;
    variable: string;
    created_at: string | null;
  })[];
}

export type ActivateOfflineBundleResponse = {
  licenses: ActivateOfflineResponseSublicense[];
  bundle_signature_v2: string;
}

export type ActivateOfflineResponseSublicense = ActivateLicenseResponse & {
  date: string,
  offline_signature: string,
};

export type ActivateOfflineResponse = ActivateOfflineResponseSublicense & {
  date: string,
  offline_signature: string,
  license_signature_v2: string,
};

export type AddConsumptionResponse = {
  id: number;
  max_consumptions: number;
  allow_unlimited_consumptions: boolean;
  allow_negative_consumptions: boolean;
  allow_overages: boolean;
  max_overages: number;
  reset_consumption: boolean;
  consumption_period: ConsumptionPeriod | undefined;
  total_consumptions: number;
  company: {
    id: number;
  };
};

export type AddFeatureConsumptionResponse = {
  id: number;
  license_id: number;
  company: {
    id: number;
  };
  total_consumptions: number;
  max_consumptions: number;
  allow_negative_consumptions: boolean;
  allow_unlimited_consumptions: boolean;
  allow_overages: boolean;
  max_overages: number;
  reset_consumption: boolean;
  consumption_period: ConsumptionPeriod;
  is_floating: boolean;
  is_floating_cloud: boolean;
  floating_timeout?: number;
  floating_users?: number;
};

export type ChangePasswordResponse = 'password_changed';

export type CheckBundleResponse = CheckLicenseResponse[];

export type CheckLicenseFeatureResponse = {
  id: number;
  license_id: number;
  code: string;
  name: string;
  metadata: JSONObjectRequired,
  metadata_string?: string;
  is_floating: boolean;
  is_floating_cloud: boolean;
  floating_in_use_devices?: number;
  expiry_date: string | null;
  feature_type: 'activation';
} | {
  id: number;
  license_id: number;
  code: string;
  name: string;
  metadata: JSONObjectRequired,
  metadata_string?: string;
  is_floating: boolean;
  is_floating_cloud: boolean;
  floating_in_use_devices?: number;
  expiry_date: string | null;
  feature_type: 'consumption';
  consumption_period: ConsumptionPeriod;
  allow_negative_consumptions: boolean;
  allow_overages: boolean;
  allow_unlimited_consumptions: boolean;
  max_consumption: number;
  max_overages: number;
  reset_consumption: boolean;
  total_consumptions: number;
};

export type CheckLicenseResponse = LicenseResponse & {
  license_active: boolean,
  license_enabled: boolean,
  license_signature: string,
  license_signature_v2?: string, // isFromPlatform only
};

export type CustomerLicenseUsersResponse = {
  company: {
    id: number;
  };
  customer: CustomerResponse;
  users: ({
    email: string | undefined;
    allow_unlimited_activations: boolean;
    first_name: string;
    initial_password: string;
    is_active: boolean;
    is_initial_password: boolean;
    last_name: string;
    license_id: number;
    max_activations: number;
    order_id: number;
    order_store_id: string;
    phone_number: string;
    total_activations: number;
  })[];
};

export type DeactivateBundleResponse = 'license_deactivated';

export type DeactivateLicenseResponse = 'license_deactivated';

export type DeactivateOfflineBundleResponse = 'license_deactivated';

export type DeactivateOfflineResponse = 'license_deactivated';

export type DeviceLicensesResponse = FormatLicenseResponse & {
  user?: LicenseUserResponse
};

export type FloatingBorrowResponse = {
  borrowed_until: string | null;
  max_borrow_time: number;
  device_id: number;
  license_id: number;
  company: {
    id: number;
  };
};

export type GetDeviceVariablesResponse = {
  id: number;
  created_at: string;
  variable?: string;
  value?: string;
  device_id: number;
}[];

export type GetUserLicensesResponse = ({
  license: FormatLicenseResponse,
  user: LicenseUserResponse,
})[];

export type InstallationFileResponse = {
  id: number;
  version: string | undefined;
  installation_file: string | undefined;
  release_date: string | null;
  hash_md5: string | undefined;
  environment: string;
  eula_link: string | undefined;
  release_notes_link: string | undefined;
  size: string | undefined;
  requires_version: string | undefined;
  channel: string | undefined;
  company: {
    id: number;
  };
};

export type OauthUrlResponse = {
  url: string;
  login_type: string;
};

export type GetProductDetailsResponse = {
  product_id: number,
  product_name: string,
  short_code: string,
  allow_trial: boolean,
  trial_days: number,
  authorization_method: AuthorizationMethod,
  floating_timeout: number,
  allow_overages: boolean,
  max_overages: number,
  prevent_vm: boolean,
  metadata: JSONObjectRequired,
  metadata_string?: string,
  company: {
    id: number
  },
  latest_version?: {
    id: number;
    version: string | undefined;
    full_link: string | undefined;
    filename: string | undefined;
    release_date: string | null;
    hash_md5: string | undefined;
    environment: string;
    eula_link: string | undefined;
    release_notes_link: string | undefined;
    size: string | undefined;
    requires_version: string | undefined;
    channel: string | undefined;
    created_at: string | null;
    updated_at: string | null;
    enabled: boolean;
    product_id: number;
  } | null,
  custom_fields?: { id: number, name: string, default_value: string }[]
};

export type ProductsResponse = ({
  id: number;
  created_at: Date;
  product_name: string;
  short_code: string;
  active: boolean;
  valid_duration?: string;
  trial_days: number;
  max_activations?: number;
  hardware_id_required: boolean;
  is_upgrade: boolean;
  company_id: number;
  allow_trial: boolean;
  enable_maintenance_period?: boolean;
  floating_users: number;
  is_floating: boolean;
  is_node_locked: boolean;
  is_user_locked: boolean;
  maintenance_duration?: string;
  subscription_duration?: string;
  default_license_type: LicenseTypes,
  max_consumptions: number;
  authorization_method: AuthorizationMethod;
  prevent_vm: boolean;
  allow_overages: boolean;
  consumption_period?: ConsumptionPeriod;
  max_overages: number;
  reset_consumption: boolean;
  is_archived: boolean;
  is_floating_cloud: boolean;
  floating_timeout: number;
  is_bundle: boolean;
  metadata: JSONObjectRequired,
  features: {
    id: number;
    code: string;
    feature_type: 'activation' | 'consumption';
    max_consumption: number;
    metadata: JSONObjectRequired,
    metadata_string?: string;
  }[];
})[];

export type SSOUrlResponse = {
  url: string;
  openid_configuration: {
    [key: string]: string | number | boolean;
  };
};

export type TrackDeviceVariablesResponse = {
  variable: string;
  value: string;
  device_id: number;
  created_at: number;
}[];

export type TrialExistingResponse = {
  license_type: LicenseTypes,
  is_trial: boolean,
  license: string,
} | {
  license_type: LicenseTypes,
  is_trial: boolean,
  license_user: string,
};

export type TrialNewResponse = {
  id: number;
  order_id: number;
  product_id: number;
  created_at: number;
  updated_at: number;
  active: boolean;
  enable_maintenance_period: boolean;
  enabled: boolean;
  is_floating: boolean;
  is_hardware_key_auth: boolean;
  is_trial: boolean;
  license_type: LicenseTypes;
  maintenance_duration: string | null;
  max_activations: number;
  max_transfers: number;
  metadata_string: string | undefined;
  metadata: JSONObjectRequired,
  prevent_vm: boolean;
  times_activated: number;
  trial_days: number;
  validity_period?: string;
  company: {
    id: number;
  };
  LicenseProductFeatures: ({
    id: number;
    product_feature_id: number;
    max_consumption: number;
    allow_overages: boolean;
    max_overages: number;
    reset_consumption: boolean;
    consumption_period?: ConsumptionPeriod;
    is_floating: boolean;
    is_floating_cloud: boolean;
    metadata: JSONObjectRequired,
    metadata_string?: string;
    floating_timeout?: number;
    floating_users?: number;
  })[];
  LicenseCustomFields: ({
    product_custom_field_id: number;
    value: string | undefined;
  })[];
  is_floating_cloud: boolean;
  floating_users: number;
  floating_timeout: number;
  allow_overages: boolean;
  max_overages: number;
  max_consumptions: number;
  valid_duration: null;
  consumption_period: ConsumptionPeriod | null;
  reset_consumption?: boolean;
  grace_period: number;
  allow_grace_period: boolean;
} & ({
  license: string;
  license_key: string;
} | {
  license_user: string;
  initial_password: string;
  license_user_id: number | null;
  max_license_users: number;
});

export type TrialResponse = TrialExistingResponse | TrialNewResponse;

export type VersionsResponse = ({
  version: string | undefined;
  release_date: string | null;
})[];

export type LicenseUserResponse = {
  id: number,
  email: string,
  first_name: string,
  is_initial_password: boolean,
  last_name: string,
  phone_number: string,
  allow_unlimited_activations?: boolean,
  max_activations?: number,
  total_activations?: number,
};

export type LicenseResponseBase = {
  id: number,
  allow_grace_period: boolean,
  allow_overages: boolean,
  allow_unlimited_activations: boolean,
  allow_offline_activation: boolean,
  can_borrow: boolean,
  custom_fields: CustomField[],
  customer: CustomerResponse,
  enable_maintenance_period: boolean,
  floating_timeout: number,
  floating_users?: number | null,
  grace_period: number | null,
  is_air_gapped: boolean,
  is_floating: boolean,
  is_floating_cloud: boolean,
  is_hardware_key_auth: boolean,
  license_key: string | undefined,
  license_template_id?: number | null,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_license_users?: number,
  max_overages: number,
  max_transfers?: number,
  metadata: JSONObjectRequired,
  metadata_string?: string,
  order_store_id?: string | null,
  prevent_vm: boolean,
  company: {
    id: number,
  },
  product_details?: ProductDetailsResponse,
  product_features: FeatureResponse[],
  start_date: string | null,
  times_activated: number,
  transfer_count: number,
  validity_period: string | null,
  is_trial: boolean,
  trial_days?: number,
  user?: LicenseUserResponse,
  license_type: LicenseTypes,
  allow_negative_consumptions?: boolean,
  allow_unlimited_consumptions?: boolean,
  consumption_period?: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
  max_consumptions?: number,
  reset_consumption?: boolean,
  total_consumptions?: number,
}

export type FormatLicenseResponse = LicenseResponseBase & {
  license_active: boolean,
  license_enabled: boolean,
};

export type LicenseResponse = LicenseResponseBase & {
  borrowed_until: string | null,
  floating_in_use_devices?: number,
  is_borrowed: boolean,
  is_expired: boolean,
};

export type FeatureResponse = {
  id: number,
  code: string,
  name?: string,
  expiry_date: string | null,
  is_floating: boolean,
  is_floating_cloud: boolean,
  floating_timeout?: number,
  floating_users?: number,
  metadata: JSONObjectRequired,
  metadata_string?: string,
} & ({
  feature_type: 'activation',
} | {
  feature_type: 'consumption',
  allow_negative_consumptions: boolean,
  allow_overages: boolean,
  allow_unlimited_consumptions: boolean,
  consumption_period: 'daily' | 'weekly' | 'monthly' | 'annually',
  max_consumption: number,
  max_overages: number,
  reset_consumption: boolean,
  total_consumptions: number,
});

export type CustomerResponse = {
  email: string | undefined;
  company_name: string | undefined;
  reference: string | undefined;
  phone: string | undefined;
  first_name: string | undefined;
  last_name: string | undefined;
  city: string | undefined;
  postcode: string | undefined;
  state: string | undefined;
  country: string | undefined;
  address: string | undefined;
  customer_account: {
      id: number;
      name: string;
      code: string;
  } | null;
  metadata: JSONObjectRequired;
  metadata_string?: string;
};

export type CustomField = {
  name: string,
  data_type: 'numer' | 'text' | 'date/time',
  value: string | undefined;
};

export type ProductDetailsResponse = {
  product_id: number,
  product_name?: string,
  short_code: string,
  authorization_method: 'license-key' | 'user',
  metadata: JSONObjectRequired,
  metadata_string?: string,
}

export type AuthorizationMethod = 'license-key' | 'user';

export type ConsumptionPeriod = 'daily' | 'weekly' | 'monthly' | 'annually';

export enum LicenseTypes {
  perpetual = 'perpetual',
  time_limited = 'time-limited',
  consumption = 'consumption',
  subscription = 'subscription',
};

// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export type JSONObjectRequired = { [key: string]: JSONValue } | {};

type JSONValue =
| string
| number
| boolean
| null
| JSONValue[]
| { [key: string]: JSONValue };

```

## Parameters and Internal Types

```typescript
export type LicensespringClientAuth = ({
  apiKey: string,
  sharedKey: string,
} | {
  clientID: string,
  clientSecret: string,
  tokenUrl: string,
});

export type LicensespringConfig = LicensespringClientAuth & {
  apiPath: string,
  publicKey: string,
  productCode: string,
  appName: string,
  appVersion: string,
  filePath: string,
  filename: string,
  gracePeriod: number,
  fileKey: string,
  airGapKey?: string,
  isGuardFileEnabled: boolean,
  hardwareIDMethod: number,
  sdkVersion: string,
  proxy?: AxiosProxyConfig,
  logLevel?: LogLevel,
};

export type LicensespringAPIConfig = LicensespringClientAuth & Omit<LicensespringConfig, 'productCode'>;

export type LicensespringConfigDef = Pick<LicensespringConfig, 'productCode'|'appName'|'appVersion'|'airGapKey'> & LicensespringClientAuth & {
  apiPath?: string,
  proxy?: AxiosProxyConfig,
  publicKey?: string,
  filename?: string,
  filePath?: string,
  gracePeriod?: number,
  fileKey?: string,
  isGuardFileEnabled?: boolean,
  hardwareIDMethod?: number,
  logLevel?: LogLevel,
  hardwareID?: string,
};

export type LicensespringAPIConfigDef = Pick<LicensespringConfig, 'appName'|'appVersion'|'airGapKey'> & LicensespringClientAuth & {
  apiPath?: string,
  proxy?: AxiosProxyConfig,
  publicKey?: string,
  filename?: string,
  filePath?: string,
  gracePeriod?: number,
  fileKey?: string,
  isGuardFileEnabled?: boolean,
  hardwareIDMethod?: number,
  logLevel?: LogLevel,
  hardwareID?: string,
};

export type LicensespringFloatingConfig = {
  apiPath: string,
  appVersion: string,
  hardwareIDMethod: number,
  sdkVersion: string,
  proxy?: AxiosProxyConfig,
};

export type LicensespringFloatingConfigDef = Omit<LicensespringFloatingConfig, 'hardwareIDMethod'|'sdkVersion'> & {
  hardwareIDMethod?: number,
};

type LicenseIdentificatorKeyBased = {
  license_key: string,
};

type LicenseIdentificatorUserBased = {
  username: string,
};

type LicenseActivationIdentificatorUserBased = {
  username: string,
  password: string,
};

type LicenseIdentificatorUserSSOBased = ({
  id_token: string,
} | {
  code: string,
}) & {
  customer_account_code: string,
};

type LicenseIdentificatiorRequired = {
  hardware_id: string,
  product: string,
  bundle_code?: string,
  license_id?: number,
};

export type Managed<T> = Omit<T, 'product' | 'hardware_id'>;

/**
 * @type {LicenseIdentificator}
 *
 * An object that identifies a License using either a license-key, user credentials or single sign-on credentials.
 * Optionally can include a `license_id` property to force a specific license is being selected.
 */
export type LicenseIdentificator = (
  XOR<LicenseIdentificatorKeyBased, LicenseIdentificatorUserBased>
) & LicenseIdentificatiorRequired;

export type LicenseActivationIdentificator = (
  XOR<LicenseIdentificatorKeyBased, LicenseActivationIdentificatorUserBased, LicenseIdentificatorUserSSOBased>
) & LicenseIdentificatiorRequired;

/**
 * @type {LicenseUser}
 *
 * An object describing a User associated to a specific license
 */
export type LicenseUser = {
  id: number,
  email: string,
  first_name: string,
  last_name: string,
  phone_number: string,
  is_initial_password: boolean,
  allow_unlimited_activations: boolean,
  max_activations: number,
  total_activations: number,
};

/**
 * @type {ProductDetails}
 *
 * An object describing the basic properties of a Product
 */
export type ProductDetails = {
  product_id: number,
  product_name?: string,
  short_code: string,
  authorization_method: 'license-key' | 'user',
  metadata: JSON,
};

/**
 * @type {Customer}
 *
 * An object describing a Customer
 */
export type Customer = {
  email: string,
  company_name: string,
  reference: string,
  phone: string,
  first_name: string,
  last_name: string,
  city: string,
  postcode: string,
  state: string,
  country: string,
  address: string,
  customer_account: string|null,
  metadata: JSON,
};

/**
 * @type {CustomField}
 *
 * An object describing a Custom Field. These are key-value pairs assigned to a Product and inherited by that product's Licenses. They can be overriden on the License level
 */
export type CustomField = {
  name: string,
  data_type: 'numer' | 'text' | 'date/time',
  value: string,
};

/**
 * @type {ProductFeature}
 *
 * An object describing a Product Feature. These are custom attributes assigned to a Product and inherited by that product's Licenses
 */
export type ProductFeature = {
  id: number,
  code: string,
  name: string,
  expiry_date: string,
  metadata: JSON,
  is_floating_cloud: boolean,
} & XOR<{
  feature_type: 'activation',
}, {
  feature_type: 'consumption',
  max_consumption: number,
  allow_unlimited_consumptions: boolean,
  total_consumptions: number,
  allow_overages: number,
  max_overages: number,
  reset_consumption: boolean,
  consumption_period: 'daily' | 'weekly' | 'monthly' | 'annualy' | null,
}> & XOR<{
  is_floating: false
}, {
  is_floating: true,
  floating_users: number,
  floating_timeout?: number,
}>;

/**
 * @type {LicenseType}
 *
 * Declares the type of License which is always one of the following:
 *
 * - *perpetual*: A perpetual license does not expire. The `is_expired` field on such a license will always be `false`.
 * Note that a perpetual *trial* license (`is_trial` flag is set to `true`) does have an `validity_period`, which refers to the end of the trial period.
 *
 * - *time-limited*: Has a `validity_period` set as a calendar date. After the date has passed, the `is_expired` flag will be set to `true`.
 *
 * - *subscription*: Uses an external source of truth such as a 3rd party service to determine the state of the License.
 *
 * - *consumption*: Permits usage metering. These licenses set a value the vendor wishes to meter, and then record the times that resource has been used.
 * Includes the following properties: `max_consumptions`, `total_consumptions`, `allow_unlimited_consumptions`, `allow_overages`, `max_overages`, `reset_consumption` and `consumption_period`.
 *
 */
export type LicenseType = 'perpetual' | 'time-limited' | 'consumption' | 'subscription';

export type LicenseFilePayload = ActivateOfflineResponse & {
  offline_signature: string,
};

export type LicenseSaved = LicenseResponse & {
  policy_id: string;
};

export type LicenseData = {
  id: number;
  allow_grace_period: boolean,
  allow_overages?: boolean,
  allow_unlimited_activations: boolean,
  allow_unlimited_consumptions?: boolean,
  borrowed_until: string | null,
  can_borrow: boolean,
  channel: string,
  consumption_period?: ConsumptionPeriod,
  custom_fields: CustomField[],
  customer: Customer,
  device_id: number,
  enable_maintenance_period: boolean
  environment: string,
  eula_link: string,
  floating_in_use_devices?: number,
  floating_timeout: number,
  floating_users?: number,
  grace_period: number,
  hardware_id: string,
  hash_md5: string,
  installation_file: string,
  is_air_gapped: boolean,
  is_borrowed: boolean,
  is_expired: boolean,
  is_floating_cloud: boolean,
  is_floating: boolean,
  is_hardware_key_auth: boolean,
  is_trial: boolean,
  license_active: boolean,
  license_enabled: boolean,
  license_signature: string,
  license_type: LicenseType,
  maintenance_period: string | null,
  max_activations: number,
  max_borrow_time: number,
  max_consumptions?: number,
  max_license_users: number,
  max_overages?: number,
  max_transfers?: number,
  metadata: JSON,
  order_store_id: string,
  prevent_vm: boolean,
  product_details: ProductDetails,
  product_features: ProductFeature[],
  release_date: string,
  release_notes_link: string,
  requires_version: string,
  reset_consumption?: boolean,
  size: string,
  start_date: string | null,
  times_activated: number,
  total_consumptions?: number,
  transfer_count: number,
  trial_days?: number,
  validity_period: DateISO8601UTC | null,
  version: string,
} & ({
  license_key: string,
} | {
  user: LicenseUser,
});

export type GuardFileData = {
  id: string,
  device_id: string,
  date_created: string,
};

export type DeviceVariable = {
  id: number,
  device_id: number,
  created_at: DateISO8601UTC,
  variable: string,
  value: string,
};

export type LicenseProductFeature = {
  id: number,
  product_feature_id: number,
  max_consumption: number,
  allow_overages: boolean,
  max_overages: number,
  reset_consumption: number,
  consumption_period: 'daily' | 'weekly' | 'monthly' | 'annually' | null,
  expiry_date: DateISO8601UTC | null,
  is_floating: boolean,
  is_floating_cloud: boolean,
  metadata: JSON,
} & XOR<({ is_floating: true } | { is_floating_cloud: true }) & {
  floating_timeout: number,
  floating_users: number,
},
{}>;

export type CreateOfflineActivationRequestPayload = {
  bundle_code?: string,
  hardware_id: string,
  hostname?: string,
  ip?: string,
  mac_address?: string,
  os_ver?: string,
  product: string,
  variables?: Record<string, any>,
  vm_info?: string,
} & ({
  license_key?: string,
} | {
  username?: string,
  password?: string,
});

export type CreateOfflineDeactivationRequestPayload = {
  bundle_code?: string,
  hardware_id: string,
  hostname?: string,
  ip?: string,
  mac_address?: string,
  os_ver?: string,
  product: string,
  vm_info?: string,
  consumptions?: number,
} & ({
  license_key?: string,
} | {
  username?: string,
  password?: string,
});

export enum HardwareIdAlgorithm {
  Default = 0,
  WindowsHardwareFingerprintId = 1,
  WindowsComputerSystemProductId = 2,
  WindowsCryptographyId = 3,
  LinuxMachineId = 4,
  CloudPlatformsId = 5,
};

/** Date string in ISO 8601 format (always in UTC timezone) with optional separators and optional time component, e.g.:
 *
 * "2024-09-27T23:30:48.016Z"
 *
 * "2024-09-27 23:30:48.016"
 *
 * "2024-09-27 23:30:48"
 *
 * "2024-09-27 23:30"
 *
 * "2024-09-27"
 *
 */
export type DateInputString = string;

/** Date string in full ISO 8601 format, e.g. "2024-09-27T23:30:48.016Z". Note: this is always in UTC timezone */
export type DateISO8601UTC = string;

/** Date string in RFC 7231 format, e.g. "Fri, 27 Sep 2024 23:30:48 GMT". Note: this is always in GMT timezone */
export type DateRFC7231 = string;

/** Length of time expressed in days, months or years, e.g. 5d, 2m, 3y */
export type TimeLength = string;

export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'off';

```

## Floating API v2 Types

```typescript
type FloatingAPIConfig = {
  apiPath: string,
  hardwareID?: string,
  hardwareIDMethod?: number,
  logLevel?: LogLevel,
  proxy?: AxiosProxyConfig,
  certChain: string,
  disableUserAuth?: boolean,
} & (
    {
      apiKey: string,
      sharedKey: string
    } | {
      clientID: string,
      clientSecret: string,
      tokenUrl: string
    }
  );

type AnyJson = Record<string, any>;
type RFC3339 = string; // RFC3339 (UTC), e.g. "2025-06-01T12:00:00Z"

interface PingResponse {
  message: string;
  version: string;
}

interface LoginResponse {
  token: string;
  expires_at: RFC3339;
  expires_in: number;  // seconds (float)
}

interface User {
  id: number;
  username: string;
  role: 'admin' | 'user';
  created_at: RFC3339;
  updated_at: RFC3339;
}

interface LoginUser {
  username: string;
  password: string;
}

interface ChangePasswordReq {
  username: string;
  old_password: string;
  new_password: string;
}

interface SetPasswordReq {
  password: string;
}

type AuthMeSuccessBody = {
  expires_at?: RFC3339;
  ExpiresAt?: RFC3339; 
  [key: string]: unknown;
};

interface CloudConfig {
  airGapPublicKey: string;
  apikey: string;
  apiprefix: string;
  baseURL: string;
  cacertificatePath: string;
  certificatePath: string;
  clientId: string;
  clientSecret: string;
  disableSync: boolean;
  id: number;
  privateKeyPath: string;
  serverPublicKey: string;
  sharedKey: string;
  syncIntervalHours: number;
  syncIntervalMinutes: number;
  useHardwareKey: boolean;
  useOAuth: boolean;
}

interface CloudConfigUpdate {
  airgap_public_key?: string;
  api_key?: string;
  api_prefix?: string;
  base_url?: string;
  client_id?: string;
  client_secret?: string;
  server_public_key?: string;
  shared_key?: string;
  use_oauth?: boolean;
}

interface AddLicenseRequest {
  product?: string;
  license_key?: string;
}

interface Company {
  id: number;
}

interface LicenseUser {
  id: number;
  email: string;
  is_active?: boolean;
  first_name: string;
  last_name: string;
  phone_number: string;
  is_initial_password: boolean;
  initial_password?: string;
  license_id?: number;
  order_store_id?: string;
  order_id?: number;
  max_activations: number;
  allow_unlimited_activations: boolean;
  total_activations: number;
}

interface ProductDetails {
  product_id: number;
  product_name: string;
  short_code: string;
  authorization_method: string;
  metadata: AnyJson | null;
  company_id: number;
  trial_days?: number;
  allow_overages?: boolean;
  max_overages?: number;
  prevent_vm?: boolean;
  floating_timeout?: number;
  validity_period?: string | null;
}

interface CustomerAccount {
  code: string;
  id: number;
  name: string;
}

interface Customer {
  email: string;
  first_name: string;
  last_name: string;
  company_name: string;
  phone: string;
  reference: string;
  address: string;
  postcode: string;
  city: string;
  country: string;
  state: string;
  customer_account?: CustomerAccount;
  metadata: AnyJson | null;
}

interface CustomField {
  name: string,
  value: string,
  data_type: string,
}

interface LicenseData {

  product?: string;
  hardware_id?: string;
  policy_id: number; // air-gapped
  is_licensed?: boolean;
  is_unlicensed_copy?: boolean;
  is_valid?: boolean;
  is_dirty?: boolean;
  local_consumptions?: number;
  last_check?: RFC3339;
  last_usage_date?: RFC3339;
  grace_period_start?: RFC3339;
  floating_vp?: RFC3339;

  custom_fields: CustomField[] | null;
  user_data?: Record<string, string>;
  metadata: AnyJson | null;

  // License Info
  id: number;
  license_active: boolean;
  license_enabled: boolean;
  is_expired: boolean;
  license_type: string;
  start_date: RFC3339 | null;
  signature?: string;
  is_trial?: boolean;
  trial_days: number;
  validity_period: RFC3339 | null;
  maintenance_period: RFC3339 | null;

  // consumption
  allow_overages: boolean;
  max_overages: number;
  max_consumptions: number;
  total_consumptions: number;
  allow_unlimited_consumptions: boolean;
  allow_negative_consumptions?: boolean;
  reset_consumption: boolean;
  consumption_period: string | null;

  // floating
  is_floating_cloud: boolean;
  is_floating: boolean;
  floating_timeout: number;
  floating_in_use_devices: number;
  floating_users: number;

  // borrowing / transfer
  max_borrow_time: number;
  prevent_vm: boolean;
  is_air_gapped: boolean;
  times_activated: number;
  max_activations: number;
  transfer_count: number;
  max_transfers: number;
  is_borrowed: boolean;
  offline_activated?: boolean;
  grace_period: number;

  // bundle
  is_bundle_activated?: boolean;
  bundle_license_id?: number;
  bundle_licenses?: LicenseData[];
  is_bundle?: boolean;

  customer: Customer;
  user?: LicenseUser;
  product_details: ProductDetails;
  license_features: LicenseFeature[];
  company?: Company;
  variables: DeviceVariable[];

  channel: string;
  enable_maintenance_period: boolean;
  environment: string;
  eula_link: string;
  hash_md5: string;
  installation_file: string;
  is_hardware_key_auth: boolean;
  offline_signature: string;
  license_signature_v2: string;
  release_date: string;
  release_notes_link: string;
  requires_version: string;
  size: string;
  version: string;
  max_license_users: number;

  allow_grace_period: boolean;
  allow_unlimited_activations: boolean;
  can_borrow: boolean;
  device_id: number;
  license_signature: string;
  order_store_id: string;
}

interface DeviceVariable {
  id?: number;
  name?: string;
  value?: string;
  variable?: string;
  created_at: RFC3339;
  device_id?: number;
}

interface LicenseFeature {
  id: number;
  code: string;
  name: string;
  feature_type: string;
  expiry_date: string;
  max_consumption: number;
  total_consumptions: number;
  local_consumptions?: number;
  allow_overages: boolean;
  max_overages: number;
  allow_unlimited_consumptions: boolean;
  allow_negative_consumptions?: boolean;
  reset_consumption: boolean;
  consumption_period: string | null;
  is_floating_cloud: boolean;
  is_floating: boolean;
  floating_timeout?: number;
  floating_users?: number;
  floating_in_use_devices?: number;
  floating_start?: RFC3339;
  floating_end?: RFC3339;
  metadata: AnyJson | null;
}

interface ActivateBundleResponse {
  status: 'ok';
  message: 'bundle added';
  license_ids: number[];
  bundle_license_id: number;
}

interface DeactivateBundleResponse {
  status: 'ok';
  message: 'bundle deactivated';
}

interface FloatingUser {
  id?: number; // ommited?
  username: string;
  email: string;
  license_id: number;
  product: string;
  product_id: number;
  floating_amount: number;
  floating_end_time: RFC3339;
  created_at: RFC3339;
  last_check: RFC3339;
  vendor_id: number;
  is_borrowed: boolean;
}

interface ActivateLicenseResponse {
  status: 'ok';
  message: 'license added';
  product: string;
  license_id: number;
}

interface AddConsumptionRequest {
  consumptions: number;
  allow_overages?: boolean;
  max_overages?: number;
}

interface ConsumptionResponse {
  id: number;
  max_consumptions: number;
  total_consumptions: number;
  allow_unlimited_consumptions: boolean;
  allow_negative_consumptions: boolean;
  allow_overages: boolean;
  max_overages: number;
  reset_consumption: boolean;
  consumption_period: string | null;
  license_signature: string;
}

interface FeatureConsumptionResponse extends ConsumptionResponse {
  is_floating_cloud: boolean;
  is_floating: boolean;
  floating_timeout: number;
  floating_users: number;
}

interface AddFeatureConsumptionRequest {
  consumptions: number;
  feature: string;
}

interface RegisterFeatureRequest {
  username: string;
  feature?: string;
  email?: string;
}
interface UnregisterFeatureRequest {
  username?: string;
  feature?: string;
}

interface AllFeatureUsersRequest {
  feature?: string;
}

interface RegisterRequestBody {
  username: string,
  role?: string,
  password: string,
}

interface RegisterRequestBodyInternal {
  Username: string,
  Role: string,
  Password: string,
}

interface UsernameRequest {
  username: string;
}

interface BorrowUserRequest {
  username: string;
  borrowed_until?: RFC3339;
}

interface BorrowResponse {
  license_id?: number;
  device_id?: string;
  borrowed_until?: string;
  license_signature?: string;
  max_borrow_time?: number;
}

interface OfflineRequestInput {
  product?: string;
  license_key?: string;
}

interface BundleRequest {
  bundle: string;
  license_key: string;
}

interface GenerateOfflineRequestResponse {
  status: 'ok';
  request_data: string; // base64 payload
}

interface GenerateAirgapRequestBody {
  initialization_code: string;
  license_key: string;
  product: string;
}

interface GenerateAirgapDeactivationRequestBody {
  initialization_code: string;
  license_key: string;
}

interface DeactivateAirgapRequestBody {
  confirmation_code: string;
  license_key: string;
}

interface SyncConfig {
  enabled: boolean;
  hours: number;
  minutes: number;
}

interface SyncEnableReq {
  enabled: boolean;
  hours?: number;
  minutes?: number;
}

interface FloatingFeatureUser {
  feature_id: number;
  username: string;
  email: string;
  license_id: number;
  feature: string;
  product: string;
  floating_amount: number;
  floating_end_time: RFC3339; 
  created_at: RFC3339;        
  last_check: RFC3339;        
  vendor_code: string;
  vendor_id: number;
}

interface FeatureCodeID {
  feature_id: number;
  feature_code: string;
  users_list: FloatingFeatureUser[];
}

type AllFeatureUsersResponse = FeatureCodeID[];

interface RegisterFeatureResponse extends LicenseFeature {
  license_id: number,
}

interface FeatureReleasedAllResponse {
  status: 'ok';
  message: 'all features released';
  license_id: number;
  feature: string;
}

interface UnregisterAllUsersResponse {
  status: 'ok';
  message: 'all users unregistered';
  license_id: number;
}

interface AirgapActivationCodeResponse {
  status: 'ok';
  hardware_id: string,
  activation_code: string,
}

interface AirgapDeactivationCodeResponse {
  status: 'ok';
  hardware_id: string,
  deactivation_code: string,
}

interface AirgapeDeactivatedResponse {
  status: 'ok';
  message: 'license_deactivated';
}

interface AirgapActivatedResponse {
  status: 'ok';
  message: 'airgap license activated';
  license_id: number;
}

```


[title] Samples
[path] SDKs/Go SDK/v2/

This section provides a guide to the core functionalities available in the SDK and how to use them effectively. It supports various license types; including online, offline, floating, consumption, and air-gapped licenses; as well as feature-specific controls.

Each license type comes with its own set of methods for activation, validation, usage, and deactivation. In this guide, you'll see how to:

- Initialize and configure the LicenseHandler
- Activate and validate licenses both online and offline
- Manage floating slots for licenses and features
- Handle consumption-based licenses and features
- Use air-gap-compatible activation and confirmation flows
- Perform local checks without needing internet access
- Retrieve and use license or feature metadata stored in local files


[title] Air-Gap License Activation
[path] Floating Server/Floating Server V1/User Interface/UI Configuration/

Airgap license activation is accessed on "Airgap license activation" tab in Configuration page in Floating server. Airgap activation is done using [**Airgap portal**](https://airgap.licensespring.com).

### 1. Air-Gap Portal Initialization

- Initialize airgap activation in Airgap portal using a license key
- Initialization code from Airgap portal will be used in the next step

### 2. Floating Server Air-Gap Initialization

- Enter the License Key and Initialization code into airgap activation page in Floating Server
- Generate activation code
- Activation code and Hardware ID from Floating server will be used in the next step

### 3. Air-Gap Portal Activation

- Start the activation process in Airgap portal, and enter the License key, Hardware ID and Activation code (from Step no. 2)
- Policy ID and Confirmation code will be used in the next step

### 4. Floating Server Air-Gap Activation

- In Floating server, set the policy ID and Confirmation code from previous step
- Retrieve license policy from [**License portal**]() for the license you are doing the activation
- Open the license policy file, and enter that code in corresponding field in Floating server
- Activate the license

**After these 4 steps, if all the data was correct, you should see your license in&#x20;**[**Products**](docId\:rsWCrpnQ1XajOtkPdHRHr)**&#x20;page in Floating server.**

[title] Generating Reports
[path] Floating Server/Floating Server V1/User Interface/

Reports page allows you to see reports and statistics about usage of licenses.

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/OQd3dpT56Vwam_-zcyXnN_screenshot-2023-06-21-at-143709.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/OQd3dpT56Vwam_-zcyXnN_screenshot-2023-06-21-at-143709.png" size="80" width="1654" height="228" position="center" caption="Reports Page" alt="Reports Page"}

After selecting a product, you are able to see detailed reports for that product:

![Detailed Product Reports](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/PX3nwBudkxpwygAdjESgE_reportzyni2tq.png "Detailed Product Reports")

## Report Types

1. Average slot usage ( Average license slot usage per day (%) )
2. Max daily users ( Maximum users logged in for each day )
3. Max slots reached ( How many times were max license slots reached per day )

**Average slot usage&#xA0;**&#x63;hart displays the average usage percentage per day over the specified time range for some product, where percentage is calculated as slotsUsed / maxSlots.
**Max daily users** chart displays maximum number of daily users for some product over the specified time range.
**Max slots reached** chart displays the maximum number of slots that was reached for the specified product on each day over the specified time range.

[title] Health
[path] Floating Server/Floating Server V1/API Reference/config/

{
  "id": "l2dBGQLK8X6Gojt5q3eTx",
  "data": {
    "url": "http://localhost:8080/api/v4/health",
    "name": "Health",
    "method": "GET",
    "request": {
      "pathParameters": [],
      "queryParameters": [],
      "headerParameters": [],
      "bodyDataParameters": [],
      "formDataParameters": []
    },
    "responses": [
      {
        "statusCode": "200",
        "description": "",
        "jsonExample": ""
      }
    ],
    "contentType": "application/json",
    "description": ""
  },
  "type": "api-oas-v2",
  "children": [
    {
      "text": ""
    }
  ]
}
[title] Security
[path] Floating Server/Floating Server V1/Best Practices/

## Traffic Encryption

In order to encrypt traffic to Floating server, we need to add an encrypting proxy that will forward requests to the Floating server. Here is an example configuration for Nginx:

```shell
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    
    # Domain name this server will listen on
    server_name  example.com www.example.com;

    listen 443 ssl;

	# Path to certificate pair
    ssl_certificate /etc/nginx/tls/cert.pem;
    ssl_certificate_key /etc/nginx/tls/key.pem;
    
    # Set TLS protocols and ciphers
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;

    # Redirect non-https traffic to https
    if ($scheme != "https") {
        return 301 https://$host$request_uri;
    }
    
    # Redirect to floating server,
    # make sure to set port to the one floating server is listening on
    location / {
    	proxy_set_header X-Real-IP $remote_addr;
      	proxy_set_header REMOTE_ADDR $remote_addr;
      	proxy_set_header Host $host;
      	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      	proxy_set_header X-Forwarded-Proto https
        
        proxy_pass http://127.0.0.1:8080;
    }
}
```

If you want a more in-depth guide on how to secure Floating server using Nginx and Certbot: [**Using Free Let’s Encrypt SSL/TLS Certificates with NGINX**](https://www.nginx.com/blog/using-free-ssltls-certificates-from-lets-encrypt-with-nginx/).

## Floating Server Password

You can enhance the security of the Floating Server by setting up a login password for the web interface. This is done by adding a hashed password to the `config.yaml` file:&#x20;

```yaml
# Password hash for website login (e.g. https://bcrypt-generator.com/)
websitePassword: $2y$10$lsiMFX54HFoPbceInt3ppe4JW7wGxuYyRJSVLDgGX5RVv4m39aTyG
```

You can also set the Floating Server password directly through the user interface. For more details, please refer to the [**Change Password**](docId\:pMCs_jYe70tHLL9Opv-Fi) section.

This ensures that users must provide the correct password to access the server's UI, adding an extra layer of protection.&#x20;

## Redis Security

If you're using Redis, it's important to secure the Docker volumes and networks to ensure that your Redis instance isn't tampered with. This is crucial in environments where data persistence and node-locking rely on Redis.&#x20;

[title] Products
[path] Floating Server/Floating Server V1/User Interface/UI Configuration/

Products tab can be found under Configuration page. It allows you to add new licenses associated with products and see which ones you already have installed.

The Products tab, located under the Configuration page, allows you to manage products and their associated licenses. A license is an instance or usage right of a product, and multiple licenses can be created for a single product to accommodate different use cases, users, or devices.

## Install a Product

### License Key Authenticated Product

To install a key authenticated license, you need is product's code and license key. Simply select "Key auth" from the dropdown and add product information to the corresponding fields.&#x20;

After a license is added using the **product code**, its corresponding **license ID&#x20;**&#x77;ill appear in the list of licenses on the **Products&#x20;**&#x70;age. This functionality was introduced in version 1.6.0, when the floating server began supporting multiple licenses for each product. This enhancement allows users to add an unlimited number of licenses for a single product.

:::hint{type="warning"}
**Note:&#x20;**&#x50;roducts need to be added using product code, not product name.
:::

![Key Authenticated Product](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/cC2YR3_JQTzchbMeB1fW7_screenshot-2023-06-21-at-141733.png "Key Authenticated Product")

### Password Authenticated Product

You can also install a password authenticated product. To do that, you need to know a product's name as well as username and password that can authenticate that product.

Select "User auth" from the dropdown and fill the form for password authenticated product.

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/9xT3JjPkioBdBeZkGvRa5_screenshot-2023-06-21-at-141755.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/9xT3JjPkioBdBeZkGvRa5_screenshot-2023-06-21-at-141755.png" size="80" width="2030" height="348" position="center" caption="Password Authenticated Product" alt="Password Authenticated Product"}

### Offline Licenses

Floating server also allows you to install offline licenses. To do that, visit the [**Generate Offline License**](docId\:l7jqMuSTfDjuaHc_Ggxj2) page and follow the instructions. Afterwards, activate the offline license like this:



![Offline License Activation](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/K4cGljTslXNLqGCTTWfwl_screenshot-2023-06-21-at-141807.png "Offline License Activation")

## Listing Installed Products and Removing Them

Products page allows you to see which products you have currently installed as well as remove them.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/0a2qcpf2-lqA-T-h8X1pI_image.png)


[title] Configuration Options
[path] SDKs/Go SDK/v2/License Handler/

## Configuration Options for License Manager

The LicenseManager in the SDK provides several configuration options that allow you to tailor its behavior to your specific use cases, including air-gapped environments, logging control, offline support, and more.

### Custom Logger (Resty)

The License Manager uses a Resty client to communicate with LicenseSpring’s API. By default, Resty logs to standard output. You can override this behavior by passing a custom logger using WithRestyLogger.

```go
WithRestyLogger(restyLogger resty.Logger)
```

```go
type CustomLogger struct{}

func (fl *CustomLogger) Debugf(format string, v ...interface{}) {}
func (fl *CustomLogger) Errorf(format string, v ...interface{}) {}
func (fl *CustomLogger) Warnf(format string, v ...interface{})  {}

lm_config := license_manager.LicenseManagerBasicConfiguration{
				OAuth:             false,
				ApiKey:            "your-api-key",
				SharedKey:         "your-shared-key",
				ProductCode:       "your-product-code",
				AuthData:          auth.FromKey("LICENSE-KEY"),
			}

lm, _ := license_manager.NewLicenseManager(
    lm_config,
    license_manager.WithRestyLogger(CustomLogger),
)

cfg.Manager = lm

lh, _ := license_handler.NewLicenseHandler(cfg)

```

### WithAirGapPublicKey

```go
WithAirGapPublicKey(airgappublickey string)
```

This option is **required** for air-gapped licenses. The AirGap public key can be found on your LicenseSpring dashboard and is separate from your API and Shared keys.

### WithGracePeriod

```go
WithGracePeriod(gracePeriod int)
```

By default, the SDK allows the license to be offline for **48 hours** before invalidating it. This option lets you customize the duration of this grace period.

### WithSyncPeriod

```go
WithSyncPeriod(syncPeriod int)
```

Sets how frequently (in seconds) the SDK should try to synchronize the license with the server.

### WithRestyVerbose

```go
WithRestyVerbose(verbose bool)
```

When set to `true`, the SDK outputs detailed logs for `LicenseClient` operations.

### WithVerifySignature

```go
WithVerifySignature(verifySig bool)
```

When enabled, this option enforces signature verification on all responses from LicenseSpring.

### WithEnableGuardFile

```go
WithEnableGuardFile(enableGuardFile bool)
```

This enables the use of **guard files&#x20;**&#x74;o protect against reuse of offline activation requests and ensure that hardware IDs match.

### WithHardwareId

```go
WithHardwareId(hardwareId string)
```

Overrides the hardware ID used to identify the device.

### WithAppName

```go
WithAppName(appName string)
```

Overrides the App Name.

### WithAppVersion

```go
WithAppVersion(appVersion string)
```

Overrides the App Version.

### WithServerPublicKey

```go
WithServerPublicKey(publicKey string)
```

Overrides the server public key used to verify the signature in API responses. Setting up this value is mandatory if you are using a server other than LicenseSpring's servers.

### WithHardwareIdAlgo

```go
WithHardwareIdAlgo(hardwareId string)
```

Overrides the hardware ID used to identify the device. You can use this configuration option if you want to enable the built-in hardware ID module, which supports multiple hardware ID algorithms. You’ll need to select one of the supported algorithms from the list below:

- HWIDAlgorithmWindowsFingerprint
- HWIDAlgorithmComputerSystemProduct
- HWIDAlgorithmCryptography
- HWIDAlgorithmLinuxMachineID
- HWIDAlgorithmCloudPlatform

Each algorithm generates the hardware ID differently depending on the operating system and environment. Choose the one that best fits your use case.

```go
const (
	Default HardwareIdAlgorithm = iota
	WindowsHardwareFingerprintId
	WindowsComputerSystemProductId
	WindowsCryptographyId
	LinuxMachineId
	CloudPlatformsId
)
```

### WithMachineId

```go
WithMachineId()
```

Overrides the hardware ID and sets it to match the machine ID used in SDK v1.
&#x20;Use this option if you want to maintain compatibility with the hardware ID format from v1.

[title] License File
[path] SDKs/node.js SDK/

For more info see:&#x20;

- [**https://docs.licensespring.com/sdks/tutorials/best-practices/local-license-file**](https://docs.licensespring.com/sdks/tutorials/best-practices/local-license-file)&#x20;
- [**https://docs.licensespring.com/sdks/python/licensefile**](https://docs.licensespring.com/sdks/python/licensefile)

To load a local license file, create an instance of LicenseManager and call the method loadLicense:

```javascript
const licenseFile = licenseManager.loadLicense();
```

The License class provides an interface for working with the License File.

## Methods

### Create Offline Request File

Creates an `activate_offline.req` or `deactivate_offline.req` file for offline activation/deactivation at the specified path:

```typescript
createRequestFile(request: OfflineActivation, offlinePath: string)

// type declaration for Offline Activation:

interface OfflineActivation {
  isActivation: boolean; // true for activation, false for deactivation
  isGuardFileEnabled: boolean; // should a guard file be created
  guard: any // guard file data if required, created using: licenseAPI.createActivationGuard(licenseKey)
  data: { // license data
    product: string,
    hardware_id: string,
    license_key?: string,
    license_id?: number,
    username?: string,
    password?: string,
    app_ver?: string,
    os_ver?: string,
    hostname?: string,
    ip?: string,
    is_vm?: boolean,
    vm_info?: string,
    mac_address?: string,
    variables?: {
      [key: string]: boolean | number | string
    },
  };
}

```

### Get Feature Data

```typescript
featureData(featureCode: string): ProductFeature
```

### Check License Status

Throws an exception if the license is disabled, inactive or expired

```typescript
checkLicenseStatus(): void
```

### Perform Full License Check

Checks License status and saves to local license file

```typescript
check(includeExpiredFeatures: boolean = false): Promise<LicenseResponse>
```

### Air-Gap License Activation Code

For more info see: [**https://docs.licensespring.com/license-entitlements/activation-types/air-gapped**](https://docs.licensespring.com/license-entitlements/activation-types/air-gapped)

```typescript
getDeactivationCode(initializationCode: string): string

deactivateAirGap(confirmationCode: string): void
```

### Deactivate License

Deactivates a License, updates local license file. Optionally deletes license file

```typescript
deactivate(deleteLicense: boolean = false): Promise<boolean>
```

### Local License Check

Performs a local check using the local license file. Throws an exception if license is not valid

```typescript
localCheck(): Promise<true>
```

### Change Password

Performs password change for user associated to License

```typescript
changePassword(oldPassword: string, newPassword: string): Promise<boolean>
```

### Add Local Consumption

Adds a License consumption to the local license data

```typescript
addLocalConsumption(consumptions: number = 1)
```

### Add Local Feature Consumption

Adds a License feature consumption to the local license data

```typescript
addLocalFeatureConsumption(featureCode: string, consumptions: number = 1)
```

### Sync License Feature Consumption

Sends a feature consumption request to the server and updates local data

```typescript
syncFeatureConsumption(feature: { code: string, local_consumption: number }): Promise<boolean>
```

### Sync License Consumptions

Syncs local consumptions to server

```typescript
syncConsumption(overages: number = -1): Promise<boolean>
```

### Borrow Floating License

```typescript
floatingBorrow(borrowUntil: string, password?: string): Promise<boolean>
```

### Release Floating License

```typescript
floatingRelease(): Promise<boolean>
```

### Check Feature

Checks License Feature status, throws exception if not active

```typescript
checkFeature(featureCode: string): Promise<void>
```

### Release Borrowed Feature

```typescript
releaseFeature(featureCode: string): Promise<void>
```

### Update Offline

Update local cache from Offline License File (at given `path`). Optionally reset local consumption value

```typescript
updateOffline(path: string, resetConsumption: boolean): boolean
```

### Deactivate License Offline

```typescript
deactivateOffline(offlinePath: string): Promise<void>
```

### Get Product Details

Retrieves Product Details from server:

```typescript
productDetails(includeLatestVersion: boolean = false, includeCustomFields: boolean = false, includeExpiredFeatures: boolean = false): Promise<ProductDetailsResponse>
```

Retrieve Product Details from local data:

```typescript
get productDetailsLocal()
```

### Device Variables

Set custom variables to local data:

```typescript
setDeviceVariablesLocal(variables: { [key: string]: string|number }, save: boolean = true): void
```

Send locally stored variables to server, optionally save to license file:

```typescript
setDeviceVariables(save: boolean = false): Promise<void>
```

Get the value of a variable from local data:

```typescript
getDeviceVariableLocal(variable: string)
```

Get all variables from local data:

```typescript
getDeviceVariablesLocal()
```

Get all variables from server:

```typescript
getDeviceVariables(): Promise<DeviceVariable[]>
```

### Getters

```javascript
get allowGraceSubscriptionPeriod()

get allowOverages()

get allowUnlimitedActivations()

get allowUnlimitedConsumptions()

get borrowUntil()

get consumptionPeriod()

get consumptionReset()

get customerInformation()

get customFields()

get daysRemaining()

get daysSinceLastCheck()

get expiryDate()

get features()

get floatingClientId()

get floatingEndDate()

get floatingInUseDevices()

get floatingTimeout()

get gracePeriod()

get gracePeriodHoursRemaining()

get id()

get isAirGapped()

get isBorrowed()

get isControlledByFloatingServer()

get isDeviceTransferAllowed()

get isDeviceTransferLimited()

get isExpired()

get isFloating()

get isFloatingExpired()

get isGracePeriod()

get isGracePeriodStarted()

get isMaintenancePeriodExpired()

get isSubcriptionGracePeriodStarted()

get isTrial()

get isValid()

get isValidityPeriodExpired()

get lastCheck()

get lastUsage()

get licenseActive()

get licenseEnabled()

get licenseKey()

get licenseType()

get licenseUser()

get localConsumptions()

get maintenanceDaysRemaining()

get maintenancePeriod()

get maxActivations()

get maxConsumptions()

get maxFloatingUsers()

get maxOverages()

get maxTransfers()

get metadata()

get policyID()

get preventVm()

get startDate()

get subscriptionGracePeriod()

get totalConsumptions()

get transferCount()

get validityPeriod()

get validityWithGracePeriod()
```

##


[title] Error Handling and Logging
[path] SDKs/Go SDK/v2/

In our SDK, we divide all errors into two primary categories:

1. **Server Errors** – returned directly from the LicenseSpring backend.
2. **Internal SDK Errors** – generated within the SDK itself.

### Error Type

We define a unified error type for all internal and server errors:

```go
type Error struct {
	Status     int                    `json:"status"`
	Code       string                 `json:"code"`
	Message    string                 `json:"message"`
	Details    map[string]interface{} `json:"details,omitempty"`
	Inner      error                  `json:"-"`
	StackTrace string                 `json:"-"`
}
```

### Server-Originated Errors

These errors are returned directly from the LicenseSpring API. We do not wrap them multiple times. Instead, we handle them as follows:

- At the **lowest point** where the API response is received, we wrap the error and add a stack trace using `debug.Stack()`.


```go
// resp is the server's response
if resp.Error != nil {			
     err := core_errors.Error{
			Status: resp.Error.Status,
			Code: resp.Error.Code,
			Message: resp.Error.Message,
			Inner: resp.Error,
			StackTrace: string(debug.Stack())
		}
```

- These errors are returned **as-is** up the call chain.
- Logging occurs only once, at the `LicenseHandler` level.

### Internal SDK Errors

For errors caused by logic inside the SDK, we have predefined constructor functions. These are always called at the **lowest layer where the error originates**, and a stack trace is attached.

Example:

```go
if !ld.IsFloatingorFloatingCloud() {
	return ld, errors.LicenseNotFloating(string(debug.Stack()))
}
```

All such error constructors follow the format:

```go
func LicenseNotFloating(stack ...string) *Error {
	e := &Error{
		Status:  http.StatusBadRequest,
		Code:    "license_not_floating",
		Message: "the license is not a floating license",
	}
	if len(stack) > 0 {
		e.StackTrace = stack[0]
	}
	return e
}
```

### LicenseHandler Layer: Logging and Safe Return

At the topmost layer (usually inside `LicenseHandler`), we:

1. **Log** the complete error including stack trace.
2. **Return** a safe version of the error (excluding stack and internal details).

```go
ld, err := lh.LicenseManager.ReleaseFloatingLicense(ctx)
if err != nil {
	logger.Error(fmt.Errorf("floating license release failed: %w", err))
	return ld, errors.SanitizeError(err)
}
```

The `SanitizeError` function:

```go
func SanitizeError(err *errors.Error) map[string]interface{} {
	return map[string]interface{}{
		"status":  err.Status,
		"code":    err.Code,
		"message": err.Message,
	}
}
```

### Example: Full Error Flow for Floating License Release

```go
func (ls *LicenseManager) ReleaseFloatingLicense(ctx context.Context) (*types.LicenseData, error) {
	if err := ls.validate(); err != nil {
		// Validation errors are returned immediately, no need to wrap.
		return nil, err
	}
	ld := ls.LicenseData

	isActive, isEnabled, isExpired := ls.CheckLicenseStatus()

	// This is the lowest level where the internal SDK error occurs.
	// We attach a stack trace using debug.Stack() and create a 
	// custom *Error object.
	if !isEnabled {
		return ld, errors.LicenseNotEnabled(string(debug.Stack()))
	}
	if !isActive {
		return ld, errors.LicenseNotActive(string(debug.Stack()))
	}
	if isExpired {
		return ld, errors.LicenseExpired(string(debug.Stack()))
	}

	if !ld.IsFloatingorFloatingCloud() {
		return ld, errors.LicenseNotFloating(string(debug.Stack()))
	}

	config := ls.LicenseClient.LicenseClientConfiguration
	authData := ld.AuthenticationData

	request := core_request.LicenseRequest{
		HardwareId: config.HardwareId,
		Product:    config.ProductCode,
		Auth:       authData,
	}

	// This error comes from the server.
	// The LicenseClient layer has already captured the stack trace.
	// We return it as-is so that the outer layer (LicenseHandler)
	// can log and sanitize it.
	err := ls.LicenseClient.FloatingRelease(ctx, request)
	if err != nil {
		return ld, err
	}

	ld.RevokeFloatingLicense()

	logger.Info("Floating License released successfully")
	return ld, nil
}

```

```go
func (lh *LicenseHandler) ReleaseFloatingLicense(ctx context.Context) (*types.LicenseData, error) {
	ld, err := lh.LicenseManager.ReleaseFloatingLicense(ctx)
	if err != nil {
		// We do all logging at the outermost layer. 
		logger.Error(fmt.Errorf("license floating release failed: %w", err))

		// We return a sanitized version of the error to avoid leaking internals.
		return ld, errors.SanitizeError(err)
	}

	s := lh.Storage
	err = s.SaveLicense(ld)
	if err != nil {
		logger.Error(fmt.Errorf("license floating release failed: %w", err))
		return nil, errors.SanitizeError(err)
	}

	return ld, nil
}

```


[title] License & License Data Objects
[path] SDKs/Android SDK/

The `License` file contains all information about the license. `License Data` class contains elements which are returned from LicenseSpring servers, it's signature is checked against the public key of LicenseSpring servers.

```javascript
public class License {
    private final LicenseData data;
    private final LicenseIdentity identity;

    private final InstallationFile installationFile;
    private final Product product;

	private final String hardwareId;
    private ZonedDateTime lastCheck;
    private ZonedDateTime lastUsage;
    private int localConsumptions;

    private transient LicenseRepository repository;
    private transient LicenseService service;

    private Boolean remoteExpired;
    private Boolean active;
    private Boolean enabled;

 
  	public static License createFromCheck(License license, CheckResponse checkResponse);
  
 	public int getMaxActivations();

  	public int getMaxConsumptions();

  	public int getTotalConsumptions();
 
  	public int getTimesActivated();
 
  	public void increaseConsumption();

	public void increaseConsumption(int increment);

    public void syncConsumptions(Context context);

    public void increaseFeatureConsumption(String feature, Context context);

    public void increaseFeatureConsumption(String feature, int increment, Context context);

    public boolean isExpired();

    public long daysRemaining();

    public long daysPassedSinceLastCheck();

    public void localCheck(Context context);

    public Product getProduct();
}
```

The `License` object can be used to check the validity of the license, add consumptions for consumption type of License. The License object is stored on disk encrypted.

[title] Docker
[path] Floating Server/Floating Server V1/Deployment Methods/

The Floating Server is also available as a Docker image, providing a flexible, containerized solution for deployment. This option is ideal for users looking for ease of scalability and isolation, making it well-suited for modern cloud or on-premise environments.

Explore the [**Installation Steps**](docId\:wYIdyC_kBs_a4WPTIV3cs) to learn how to set up the LicenseSpring Floating Server using a Docker image, and visit the [**Troubleshooting**](docId\:HsJXnPrBWPx64YwKr-1F-) section for answers to common questions.

[title] Database Options
[path] Floating Server/Floating Server V1/Deployment Methods/Configuration/

When deploying the Floating Server, you have two database options:

**1. Redis**

- A fast and scalable database ideal for environments requiring high performance. Redis is supported from version 1.4.10 onwards.
- Example Configuration:

```yaml
database:
  type: redis
  addresses: 
    - localhost:6379
```

**2. File-Based Database**

- An embedded option, ideal for Windows environments or smaller-scale deployments.&#x20;
- Example Configuration:

```yaml
database:
  type: file
  addresses: 
    - database
```


[title] Python Changelog
[path] SDKs/Python SDK/

## 3.11.0 (11.2.2025)

- **Added** - license feature borrow support

## 3.10.0 (8.1.2025)

- **Added** - SSO support on the `floating_borrow` method
- **Added** - optional `device_variables` to `deactivate_offline`

### 3.9.0 (4.12.2025)

- **Added** - `activation_date` getter to the `License` object

### 3.8.2 (14.11.2025)

- **Fix** - handling non ascii characters

### 3.8.1 (11.11.2025)

- **Fix** - handling feature local consumptions

### 3.8.0 (28.9.2025)

- **Added** Floating server v2 support
- **Added** support for the offline signature v2
- **Removed** support for the python 3.9 version ([**EOL**](https://devguide.python.org/versions/))

### 3.7.0 (13.6.2025)

- **Added** bundle support
- **Added** company getter on License object

### 3.6.1 (23.5.2025)

- Code improvements via refactoring

### 3.6.0 (25.4.2025)

- **Added** `product_details` method inside the `LicenseManager`
- **Added** [**demo app**](https://sdk.licensespring.com/Python%20SDK/v3.6.0/sample_app.zip)

### 3.5.0 (24.3.2025)

- **Added** optional param `env` on `license check` and `product details`

### 3.4.1 (17.3.2025)

- **Fix&#x20;**- Windows licensefile path setter method

### 3.4.0 (5.3.2025)

- **Added** OAuth support

### 3.3.0 (14.2.2025)

- licensefile
  - **Added** `get_sso_url` (SSO) method

### 3.2.0 (5.2.2025)

- **Packages update**:
  - Updated `requests` from `2.31.0` to `2.32.3`
  - Updated `pycryptodome` from `3.19.0` to `3.21.0`
  - Updated `winregistry` from `1.1.1` to `2.1.0`
  - Updated `charset-normalizer` from `3.3.0` to `3.4.1`
  - Updated `idna` from `3.4` to `3.10`
  - Updated `urllib3` from `2.0.7` to `2.3.0`
- As of [**Python 3.8's end of life**](https://devguide.python.org/versions/), we no longer support **Python 3.8**. Please upgrade to **Python 3.9 or later**.

### 3.1.8 (3.2.2025)

- License agreemnt updated
- **Added** the new hardware id provider: `HardwareIdProviderSource`
- licensefile
  - **Added** `order_store_id` method

### 3.1.7 (11.11.2024)

- **licensefile**
  - **Added** `allow_negative_consumptions` support
  - **License**
    - Methods: `check`,`deactivate`,`sync_feature_consumption`,`sync_consumption`,`floating_borrow`,`floating_release`,`check_feature` are supported for **Floating Server**
- **Added** `FloatingAPIClient`
  - **Added** `auth`, `register_user`, `unregister_user`, `unregister_all`, `borrow`, `add_consumption`, `add_feature_consumption`, `feature_register`, `feature_release`
- **Added** `FloatingManager`

### 3.1.6 (3.10.2024)

**licensefile**

- **LicenseManager**
  - **Added** `get_air_gap_activation_code`
  - **Added** `activate_air_gap_license`
- **License**
  - **Added** `get_deactivation_code`
  - **Added** `deactivate_air_gap`

### 3.1.5 (18.09.2024)

**licensefile**

- **Added** `BaseManager` object:
  - **Added** `current_config`, `reconfigure`, `is_license_file_corrupted`, `clear_local_storage`, `data_location`, `license_file_name`
- LicenseManager:
  - **Added** `get_version_list`
  - **Added** `get_installation_file`
  - **Added** `get_customer_license_users`
  - **Added** `get_user_licenses`
  - **Added** optional argument `throw_e` inside `is_online` method

**api**

- **Added** `user_licenses`

### 3.1.4 (23.08.2024)

**licensefile**

- removed `get_custom_field` method from License

### 3.1.3 (21.08.2024)

**API**

- added optional `license_id` argument to support user based licensing

**licensefile**

- added `DateTimeHelper` for handling time operations
- added optional `unique_license_id` argument to support user based licensing
- added various getter methods

### 3.1.1

**API**

- &#x20;added optional `variables` argument to `activate_license` and `activate_offline_dump` methods&#x20;

**licensefile**

- added **FeatureWatchDogs** : `setup_feature_watch_dog`, `stop_feature_watch_dog`

### 3.1.0

**Licensefile**

- **Added Device Variables** :`get_device_variables`, `get_device_variable`, `send_device_variables` and `set_device_variables`
- **Added Product Details**: `product_details`
- **Added Trial key**: `get_trial_license`
- **Grace period bug fix** (exception argument added)

### 3.0.0

**API**

- removed unused `hardware_id` argument from `activate_offline_load` method&#x20;
- added `check_offline_load` method for reading license refresh files&#x20;
- removed `password` argument from `deactivate_license`, `deactivate_offline_dump`, `add_consumption`, `add_feature_consumption`

**Licensefile**

- added argument `password` on `floating_borrow`method
- added offline activation and deactivation&#x20;
- guard file&#x20;
- update offline license method

:::hint{type="warning"}
&#x20;**Breaking changes:**

**API**

- removed **unused arguments from:&#x20;**`activate_offline_load`, `deactivate_license`, `deactivate_offline_dump`, `add_consumption, add_feature_consumption`

**Licensefile**

- **added argument** `password` on `floating_borrow`method
:::

### 2.0.1

**API**

- added optional `bundle_code` argument to `APIClient` methods which also accept \`product\` argument

**Licensefile**

- Added functionality for working with local license
- Added consumption feature
- Added borrowing and releasing of floating license
- Added license feature check
- Added thread safety for licensefile
- Watchdog
- Added license monitoring in a background threads
- Support for 3.8+ Python version

### 2.0.0

- `hardware` - hardware id provider logic extracted from `api` to its own `hardware` module
- `webhook` - added `webhook` module for receiving and validating webhook events
- `api` - APIClient methods `deactivate_license`, `deactivate_offline`, `floating_release`, `change_password` and `floating_feature_release` return textual data as received instead of boolean
- `licensefile` - added `licensefile` module used for working with local license files

### 1.3.1

- added `include_latest_version` and `include_custom_fields` optional arguments to `product_details`

### 1.3.0

- `track_device_variables` returns device variables data instead of a boolean
- added `check_license_feature` and `floating_feature_release` api functions
- deprecated signature v1 checks
- added signature v2 check on every response with returned content
- updated dependencies

### 1.2.0

- Added SSO params for license activation

### 1.1.0

- Added `PlatformIdProvider`

### 1.0.7

- Fix SDK version definition

### 1.0.6

- Added license signature v2 check on offline activation

### 1.0.5

- Added `response_type` argument for `sso_url` function

### 1.0.4

- Added license signature v2 check

### 1.0.3

- Docs typo fix (add\_consumption -> add\_feature\_consumption)


[title] Role-Based Access Control
[path] Floating Server/Floating Server V1/

Starting from version 1.5.0, for role-based access control (RBAC), the following functionalities have been added to the floating server:

- **Two Roles:** Admin and User.
- Any individual accessing server functionality must be assigned either an Admin or User role.
- **Admin Permissions:**
  - Add new users and admins.
  - Add and remove licenses (online, offline, and air-gapped).
  - Configure license and management API URLs.
  - Set shared and API keys.
- **User Permissions (Admins and non-admin users):**
  - Register as a floating user.
  - Add consumptions.
  - Access reports.
  - Check server health.
  - Borrow licenses.
  - Change their own password.

This RBAC model applies to both browser and API access.

## Start the Server

To start the server in authentication mode, use the following command:

:::BlockQuote
./floating-server -userAuthentication true
:::

## API Access


For API access, users must first log in and obtain a JWT, which is then included in subsequent requests. An example is shown below.

If a user attempts to register without logging in, they will receive an error prompting them to log in first.

```curl
curl -X POST "http://localhost:8080/api/v4/register" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
  "product": "test",
  "user": "user1",
  "os_hostname": "",
  "ip_local": "0.1.1.1",
  "user_info": "",
  "registered_at": "2024-08-26T12:21:59.776731-07:00",
  "borrowed_until": "0001-01-01T00:00:00Z"
}'
```

:::BlockQuote
Response:

\{"message":"Unauthorized: Please log in"}
:::

To log in, users send a request containing their username and password to the `/auth`endpoint. An example is shown below.

```curl
curl -u 'username':'password' http://localhost:8080/auth -H "Accept: application/json"
```

:::BlockQuote
Response:
\{"message":"Login successful","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidXNlciIsInVzZXJuYW1lIjoidXNlcjEifQ.laskPwD\_z36WjODEGKNpVojnouqXYCtKr9HXrLPBqWw"}
:::

This endpoint returns a JWT, which the user must then include in subsequent requests. After receiving the token, the user can resend the registration request using the JWT for authentication.

:::BlockQuote

:::

```curl
curl -X POST "http://localhost:8080/api/v4/register" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidXNlciIsInVzZXJuYW1lIjoidXNlcjEifQ.laskPwD_z36WjODEGKNpVojnouqXYCtKr9HXrLPBqWw" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
  "product": "test",
  "user": "user1",  
  "os_hostname": "",
  "ip_local": "0.1.1.1",
  "user_info": "",
  "registered_at": "2024-08-26T12:21:59.776731-07:00",
  "borrowed_until": "0001-01-01T00:00:00Z"
}'
```

The registeration is successful.

## Browser

The login page in authentication mode:

![login page](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/KlUJ0lq4Y8zITRZ86rl_F_screenshot-2024-08-30-at-31323-pm.png)

The **Users Management** tab displays a list of all users and their assigned roles.

- **Admin Permissions:**
  - Admins can add new users or remove existing ones.
  - When adding a user, the admin assigns a temporary password, which the user must change upon their first login.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/s3PtGyNzF8D8R5OJTYbEf_image.png)

Users and admins can change their own password form the **Change password** tab:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/yMIrJsVzcAl--VEfAeUxn_screenshot-2024-08-30-at-31631-pm.png)

If a non-admin user attempts to perform actions restricted to admins, they will receive an error message, as shown below.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/VCu4XJRIEtfbsjGclen74_screenshot-2024-08-30-at-31820-pm.png)

## Initialize Users

### Initializing the First Admin User

The first admin user can be set up during the server initialization by adding a password hash to the config/config.yaml file in the following format:

1. Generate the SHA-256 hash of the admin's password.
2. Enter this hash into the config file as shown below. This will create an admin user with the username "admin," and the specified password will be registered in the server's database. This admin can then add other users later.

Example YAML format for admin setup:

```yaml
Password hash for website login (e.g. https://bcrypt-generator.com/)
websitePassword: $2y$10$lsiMFX54HFoPbceInt3ppe4JW7wGxuYyRJSVLDgGX5RVv4m39aTyG
```

Here’s an improved version of the text for your documentation:

### Initializing the First Admin User

The first admin user can be set up during the server initialization by adding a password hash to the config/config.yaml file in the following format:

1. Generate the SHA-256 hash of the admin's password.
2. Enter this hash into the config file as shown below. This will create an admin user with the username "admin," and the specified password will be registered in the server's database. This admin can then add other users later.

Example YAML format for admin setup:

```yaml
Password hash for website login (e.g., https://bcrypt-generator.com/)
websitePassword: $2y$10$lsiMFX54HFoPbceInt3ppe4JW7wGxuYyRJSVLDgGX5RVv4m39aTyG
```

### Note on Version 1.5.0

In version 1.5.0, user initialization in the config file allowed multiple users with any role to be specified. However, this was restricted starting in version 1.5.1 and later versions. In version 1.5.0, the configuration format for multiple users looked like this:



```yaml
users:
  user1:
    username: user1
    password: pass1
    role: user

  user2:
    username: user2
    password: pass2
    role: admin
```

Starting from version 1.5.1, user initialization is limited to a single admin user at the setup stage.

### Number of Admins

At least one admin is required when running the server in authentication mode. If no admin is configured, the server will fail to launch, displaying an error message requesting you to provide the necessary configuration.

### Storage

User information is stored in the database, and passwords are securely stored as hashed values.


[title] Swift/Objective-C SDK
[path] SDKs/

## Swift/Objective-C SDK

- LicenseSpring.framework
- Sample app project
- Documentation

[**LicenseSpring\_Apple\_SDK\_v6.12.12.zip**](http://sdk.licensespring.com/Apple%20SDK/v6.12.12/LicenseSpring_Apple_SDK%20v6.12.12.zip)

**Note:&#x20;**&#x46;or Static Linking, please specify the the linker flag "-ObjC" for the library. Otherwise, please link against the dynamic version of SDK.

### Release Notes

### October 13, 2025, v6.12.12

- XCode 26 and Swift 6 Support
- License features and license features watchdog

### September 26, 2025, v6.12.11

- Virtual machine detection
- License reconfiguration support

### September 10, 2025, v6.12.10

- Guard file for offline activations
- Allow negative consumptions

### July 15, 2025, v6.12.9

- License bundle feature

### June 25, 2025, v6.12.8

- license activation date, validity duration and company getter added
- License.fullCheck performance improvements

### May 12, 2025, v6.12.7

- Set default Configuration Public key to production instead of staging environment

### April 29, 2025, v6.12.6

- Added escaping method support for non blocking functions
- Resolved previous issues with offline

### April 14, 2025, v6.12.5

- `oAuth` support
- Fix inverted maintenance period expired value

### April 1, 2025, v6.12.4

- `LicenseId` support
- Added encoding to query params when sending GET requests
- Added optional \`env\` param support

### February 11, 2025, v6.12.3

- Include license into the SDK build

### January 30, 2025, v6.12.2

- Fix issues with license online check

### November 07, 2024, v6.12.0

- Exposed `OrderStoreId` as public API
- Fixed issues with Xcode 16 and SwiftUI Preview

### October 24, 2024, v6.11.0

- Refine all errors to satisfy internal requirements and customer needs&#x20;
- Add support for Swift Package Manager
- Fix some minor issues

### October 19, 2023, v6.10.0&#x20;

- Implement local grace period
- Update README

### September 19, 2023, v6.9.0&#x20;

- &#x20;Implement AirGap deactivation
- Implement \``isAirGapActivated`\` and \``polocyID`\` license properties

### August 1, 2023, v6.8.0&#x20;

- Improve signature checks for Offline activation
- Implement `unlimited consumption` feature
- Implement `reset consumption` feature

### June 8, 2023, v6.7.0&#x20;

- Added support for metadata functionality.

### April 24, 2023, v6.6.0&#x20;

- air-gap license activation
- customization of HTTPs proxy for SDK requests
- extend demo to support air-gap activation

### January 26, 2023, v6.4.2

- FloatingServer support though FloatingClient implementation
- Add Support for Grace Period
- Add support of "date\_header\_invalid" error
- Add sending app version, name, etc. with URL and Offline requests
- Fix Demo with different configuration types (LicenseManager and FloatingClient)

**Note:**

Objective-C is now deprecated. Starting with versions 7.x.x, our SDK will no longer include it. Please contact us for options if you require support for the Objective-C language.

### December 08, 2022, v6.3.0

- Added support for Online Floating licenses
- Added Floating License Borrowing support
- Improvement of SSO demo
- Added demo for Floating Licenses
- On-the-fly configuration in demo
- Fix issue for case when the License is deleted on the Server
- Fix sending of ip/MAC with URL requests

### October 10, 2022, v6.2.1&#x20;

- Improvement handling local consumptions
- Implemented Demo application. Min OS supported version is 10.15
- Relaxed requirements on `init `methods of public types
- Exposed some public methods of License and Configuration (non-breaking)

### &#x20;August 29, 2022, v6.1.1

- Fixed extra network communication on offline activation

### August 15, 2022, v6.1.0&#x20;

- Fixed offline activation issue when `Customer.email` is null
- Fixed offline activation files lookup (now you can specify either file or folder)
- Implement getting device variables list
- Implement getting license users list by customer

### &#x20;August 9, 2022, v6.0.1

- Fixed issue with code signing
- Improved documentation

### July 29, v6.0.0

- redesign SDK in Swift

### May 3, 2022, v5.11.0

- Add retrieving of SSO url
- Add license activation with SSO token
- Add SSO token parsing from redicrection URL
- Update Mac/Swift example to show dealing with SSO
- Extend Customer with additional fields
- Add license policy and customer optional parameters when requesting trial license
- Minor improvement of interfaces
- Internal bugfix

### March 30, 2022, v5.10.1

- fixed issue related to license activation

### March 29, 2022, v5.10.0

- Added external logging subsystem. Now customers are able to collect internal (but not sensitive) logs of LicenseSpring
- Improved error reporting mechanism. Unified all errors and error codes
- Added customization in dealing with path to ls\_activation.lic file
- Added support of 'start\_date' to the license
- Implemented offline license update
- Minor improvement of interfaces
- Internal bugfix

### March 02, 2022, v5.9.0

- fixed bugs related to license file path
- set license status to inactive in case of device id mismatch error
- SDK is now shipped as a unified XCFramework and covers macOS, iOS, iOS Simulator, macCatalyst

### October 27, 2021 v5.8.0

- Updated Examples for Xcode 12.
- Added Examples for Xcode 13.
- Updated Documentation.
- Updated rules for saving license in a local file, fixed issue with incorrect last check date.
- Fixed algorithm for getting a trial license.
- Extended `InstallationFile`. Added new fields.

### August 05, 2021 v5.7.3

- Added SDK for ARM processors, see SDK/ARM/LicenseSpringMac.framework.
- Updated MacOS example for ARM architecture, added brief readme files for samples.

### May 24, 2021 v5.7.2

- Fixed incorrect Offline License file request
- Updated Examples for Mac OS

### Mac December 12, 2020 v5.7.1\_StaticLib (NEW)

- Updated Apple Universal Binary for macOS apple silicon processors static library

### Mac November 25, 2020 v5.7.1\_StaticLib

- Added Apple Universal Binary for macOS and IOS Swift/Objective C static library

Note: The archive now also contains Apple Universal Binary static library macOS and IOS. The code has not been changed.

### Mac November 6, 2020 v5.7.1

- Fixed incorrect display license status.
- Fixed `License.IsValide` for display actual data.
- Removed printing a list of network interfaces.

### Mac October 16, 2020 v5.7.0

- Added Swift iOS example project.
- Added ObjC iOS example project.
- Added local check for license. See License.localCheck.
- Added SDK for iOS platform.
- Fixed getting IP address for macOS.

### Mac October 8, 2020 v5.6.0

- added iOS Example Project;
- fixed crash;
- added checking signature on iOS;

### Mac September 10, 2020 v5.5.0

- Added `LicenseFeature.Name`, now it's possible to get License feature name not only code.
- Added new exception types `MaxFloatingReachedException` and `DeviceBlacklistedException` and `MissingEmailException` and `InvalidOrderIDException` and `MaxFloatingReachedException`.
- Implemented Overages feature for Consumption license type. See `License.IsConsumptionOverageAllowed` and `License.MaxConsumptionOverage`.
- Improved consumption handling. Added new methods `License.UpdateFeatureConsumption`, `LicenseFeature.LocalConsumption`.
- Fixed issue for validity and maintenance periods in case of null dates (unlimited periods).

### Mac August 27, 2020 v5.4.1

- Fixed issue of automatic license checks

### Mac April 1, 2020 v5.4.0

- Added `LicenseFeature name` Allowing to retrieve the feature name in addition to its code.
- Bug: Fixed issue of consumption features. Consumption changes were not stored to local license file properly.
- Bug: Fixed license status.
- Default license file path changed to `SupportApplication%AppName%\LicenseSpring%ProductCode%\License.key`. Now the default license path of the application license will be transferred to the new location by the SDK.
- In LicenseManager `sendCustomData` renamed to `sendDeviceData`.
- Added `validityPeriodUTC` `maintenancePeriodUTC` `lastCheckDateUTC`
- `ProductDetails` information now also available for offline activated licenses, see `License getProductDetails`.
- Added `License owner`
- Added `License isMaintenancePeriodExpired`
- Added `LicenseManager isOnline`
- Added new `LicenseManager getTrialLicense` method. It accepts Customer object, when issuing trial license also new customer will be created or license will be assigned to existing customer.
- Updated documentation.

### Mac March 16, 2020

- Updated examples for Xcode 10 and Xcode 11.
- Added examples for Trial Flow App.

### Mac December 27, 2019

- Added new API request `GetProductDetails`, new class `ProductDetails`.
- Added `LicenseSpringConfiguration.getAPIVersion` property. It returns API version that SDK uses.
- API version field added to offline activation/deactivation files.
- Added requests for creating licenses and orders. See `LicenseManager.createLicense` and `LicenseManager.createOrder`.
- New classes `Customer`, `OrderDetails `and `LicenseDetails`.
- Improved samples.

### Mac December 11, 2019

- User-based licensing
- Offline licensing. New API methods - `getOfflineActivationFile`, `activateLicenseOffline` and `deActivateOffline`.
- Added new methods `isOfflineActivated`.
- Added new methods `maxActivations` and `timesActivated`.
- New API request `sendCustomData`, it allows sending custom data to the platform. Data will be linked to a device, so on the platform see device variables.
- Changed license status logic, now it's possible to check whether license is active even if it was disabled. See `isActive`, `isEnabled`.

### Mac November 28, 2019, v4.5.0

- Fixed incorrect work of the SDK when product configured to have more than 2 letters short-code.
- Updated code style
- Fixed bug with LicenseStatus

### Mac September 11, 2019, v4.4.1

- Added new feature - Custom product (license) data fields, see `getcustomFields` in `License` and CustomField.h
- Improved SDK samples
- Added sending "hostname" and and ability to disable it
- Fixed API URL in samples
- Sending of optional parameters like app\_ver, os\_ver, sdk\_ver.

### Mac June 13, 2019, v4.4.0

- Added Signature verification.
- Stability and performance improvements.

### Mac June 5, 2019, v4.3.2

- Updated local check of the license, fixed issue with changing system time.

### May 8, 2019, v4.3.1

- Extended sample apps with brief example on how to handle product updates.

### May 6, 2019, v4.3.0

- Consumption licensing
- Global optimizations, significant improvements in the SDK architecture and design
- Added Swift sample

### April 18, 2019, v4.2.1

- Ability to set custom hardware ID.
- `LSExtendedOptions`, all optional SDK configuration properties now brought together in ExtendedOptions class, see sample app for details.
- Updated Example app.

### April 15, 2019, v4.1.0

- License status, `isActive` now replaced with `LicenseStatus` for the License class, for more details see LicenseStatus.h
- Fixed build error due to missed header in License.h

### April 9, 2019, v4.0.10

- implemented offline validation of the license

### April 8, 2019, v4.0.9

- added product features
- optimized license api calls

### April 5, 2019, v4.0.8

- added "product" (short-code) in relevant APIs (internal)

### April 4, 2019, v4.0.7

- fixed non-compilable code and add staging variable for Debug/Release configuration

### April 3, 2019, v4.0.6

- in case of no internet connection or other connectivity issue, `CheckLicense `will return the current License (if avail.)

### April 2, 2019, v4.0.5&#xD;

- removed `isEnabled `property from License object
- added `isExpired `property to License object. This property (bool) will now reflect whether current license is maybe expired (validity period passed). Developers should use the following logic to determine whether there is a valid license: `if license != nil && license.isExpired == false ...`


[title] Configuration File
[path] Floating Server/Floating Server V1/Deployment Methods/Configuration/

Configuration file needs to be supplied to the server at the default or custom location. Server accepts `.yaml` files.&#x20;

The only required configuration includes specifying the database config.&#x20;

:::hint{type="warning"}
On versions prior to 1.4.9 the database settings were set via the redis config.&#x20;
In version 1.4.9 and later redis config was changed in favor for database. f

**Config files made for versions prior 1.4.9 will continue to be valid.**
:::

:::hint{type="danger"}
**Changing the database type from redis to file and vice versa is not possible.&#x20;**&#xA;To change the database type all licenses need to be reactivated!
:::

**Verbose Error Logging Enhancement (Starting from Version 1.4.12)**

From version 1.4.12 onwards, verbose error logging has been introduced, providing more detailed insights into system behavior. By default, these logs are directed to stdout, making them easily accessible through Docker logs when using containers.

If you prefer to export the logs to a file, this behavior can be configured in the settings. Simply update the configuration file with the following directive:

:::BlockQuote
logDestination: exportFile
:::

Additional details can be supplied either in the configurations or through the Floating Server UI.

Configuration format:

```yaml
# Database Settings - MANDATORY
database:
  type: redis | file # If not set redis is used by default
  addresses: 
    # If type set to redis enter your redis address and port
    # If type set to file, enter the relative path where to store the files
    - redis:6379
  # - database - creates a folder database in the location from which the executable was ran

# Database config for > 1.4.9 - only redis was supported
# redis:
#  addresses:
#    - "localhost:6379"
    
# Override for default License and Management APIs
# Do not configure if not instructed by vendor
apiUrl: https://subdomain.YOUR_WHITLABEL_DOMAIN.tld
managementUrl: https://subdomain.YOUR_WHITLABEL_DOMAIN.tld

# API and shared keys for talking to LS API
apiKey:  <your_api_key>
sharedKey: <your_shared_key>

# All products this user has licenses for
products:
  # add a key based license
  MicrosoftWord:
    licenseKey: GFEV-H2YD-63EK-LMAP
  # add an username based license 
  Skype:
    username: user
    password: pass

# Password hash for website login (e.g. https://bcrypt-generator.com/)
websitePassword: $2y$10$lsiMFX54HFoPbceInt3ppe4JW7wGxuYyRJSVLDgGX5RVv4m39aTyG
    
ui:
  disableUnregistration: false
```

### Program Arguments

Floating server accepts the following arguments:

| Argument Name   | Default                    | Description                 |
| --------------- | -------------------------- | --------------------------- |
| port            | "8080"                     | Server port                 |
| config          | "config/config.yaml"       | Configuration file location |
| logfile         | "logs/floating-server.log" | Log file location           |
| data            | "data/"                    | Local database location     |
| logo            |                            | Logo file location          |
| welcomeMessage  |                            | UI welcome message          |


[title] Remove license
[path] Floating Server/Floating Server V1/API Reference/license/

{
  "id": "z-qbmCY17SzY2nstK38NI",
  "data": {
    "url": "http://localhost:8080/api/v4/removeProduct",
    "name": "Remove license",
    "method": "GET",
    "request": {
      "pathParameters": [],
      "queryParameters": [
        {
          "kind": "optional",
          "name": "product",
          "type": "string"
        }
      ],
      "headerParameters": [],
      "bodyDataParameters": [],
      "formDataParameters": []
    },
    "responses": [
      {
        "statusCode": "200",
        "description": "",
        "jsonExample": ""
      }
    ],
    "contentType": "application/json"
  },
  "type": "api-oas-v2",
  "children": [
    {
      "text": ""
    }
  ]
}
[title] registration
[path] Floating Server/Floating Server V1/API Reference/


[title] Stripe Example Use Cases
[path] Integrations/Stripe/

## 1.Two Different License Types for the Same Product

If you want your customers to be able to buy two different licenses types (and with different custom fields) from the same product here is how you would approach this use case:

### **Create the necessary custom fields that you need / want inside your product in LicenseSpring**

To do so, go to your LicenseSpring platform, click on the **Products tab**, once in the products tab, click on the product you want to use, and then click on the **Custom fields&#x20;**&#x73;ection of your product. Inside the Custom fields section click on the **"Add custom fields"**

A small pop-up window will show up. Fill out the necessary details, and click on the "Confirm" button. Do so for each custom field that you need.

![Add custom fields](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/lLSRiAtle0jQAm4z9kNCJ_screenshot-2024-03-21-at-130919.png)

### Create the necessary license policies for each of the license types you want your customers to buy

Now you will need to create a license policy for each license type you want to sell. To do so, on the product where you created the custom fields, go to the **License policies** section and click on the "**Add license policy**".

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/UqwtuNTJtLFI91fl7V6vx_screenshot-2024-03-21-at-135830.png)

A pop-up will show up with all the necessary options that you need for your licenses. Be sure to choose all the correct options that you need (for example, if you want a subscription type license, choose the subscription type from the dropdown)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/glbyRtxugnHYvaRGYhUo9_screenshot-2024-03-21-at-143315.png)

License Policies override some settings from the product itself, but they wont change the actual settings on the product.

So if you need to change the value of some custom field or product feature you can do so in this current pop-up window.

By selecting that **custom field** section of the pop-up, and choosing which custom fields you want to use on this license policy, you will get the option to change their default values.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/bQ7bdL2AjhnvAu4LmTe1H_screenshot-2024-03-21-at-144321.png)

### Create a price for each License type you want to sell inside Stripe and add the License policy code in their metadata

Now we need to go back to Stripe, and for the **LicenseSpring product** that we created the **custom fields** and **license policies,** we need to find the corresponding **Stripe product&#x20;**(if you do not have the same product created in Stripe and connected with the same product in LicenseSpring, you can do so by following the initial Stripe integration setup documentation [**https://docs.licensespring.com/integrations/stripe/integration**](https://docs.licensespring.com/integrations/stripe/integration))

Once we are inside the corresponding product page if we do not already have 2 different prices inside that product, we need to create them and add the License Policies codes in their metadata. To create a new price click on the&#x20;**&#x20;"Add another price"** and inside the new window fill out all the necessary information regarding that price and licenses.

Next step is to add the metadata. We need to click on the price for which we want to associate the newly created license policie, this will open the **Price page.&#x20;**&#x49;nside the price page click on the **"Edit metadata"** button to add all the necessary **"Custom attributes"** that you have, together with the **license policy code.**

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/4X635XHCGg9m838tWoBNt_screenshot-2024-03-21-at-150206.png)

More information on how to do so, you can find in the Stripe integration setup documentation [**https://docs.licensespring.com/integrations/stripe/integration#FfhZJ**](https://docs.licensespring.com/integrations/stripe/integration#FfhZJ).

But in simple terms, you need to add the **attribute**`license_policy` and its code that you can get back in LicenseSpring where we initialy created the two new license policies

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/IFpLG9FcuX2Rsgu0AahJz_screenshot-2024-03-21-at-155500.png)

Example custom attibute for a license policy:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/prhtH5fbquzhpKk9HWm93_screenshot-2024-03-21-at-155444.png)

### Double check everything

At the end, make sure you have inside LicenseSpring setup **2 different license policies** on the product that you want to sell (together with any custom fields or features), and that inside Stripe you have **2 different prices** with **2 different price metadatas** setup, each with its **own** correct License Policy and correct custom attributes that you want to use.

[title] Integrations
[path] Frequently Asked Questions/

## I have a Wordpress website and I want to be able to issue license keys from my LicenseSpring account?

If you are using Stripe for collecting payments, you could setup our integration with that: [**https://docs.licensespring.com/integrations**](https://docs.licensespring.com/integrations)

Otherwise, you should look at our management API. The order creator endpoint is what you're looking for:
[**https://docs.licensespring.com/management-api/order/create-order**](https://docs.licensespring.com/management-api/order/create-order)




[title] Admin and User Operations
[path] Floating Server/Floating Server V2/

## User Management & Role-Based Access

The Floating Server has **two types of users**:

### 1. Administrators

- Manage the server.
- Activate or deactivate licenses by adding or removing them from the Floating Server.
- Manage users who can register (check out) licenses.

### 2. Management Users

- Managed by administrators.
- Can register/unregister to licenses added to the Floating Server.
- Can send license and feature consumption data back to the server, usually via a client application.

:::hint{type="success"}
**Authentication:**

- By default,**&#x20;both admin** and **user&#x20;**&#x61;ctions require authentication.
- If **DisableUserAuth** is set to **false** in the configuration file, only **admin&#x20;**&#x61;ctions **require authentication**; users can perform actions without logging in.
:::

- By default, both admin and user actions require authentication.
- If DisableUserAuth is set to false in the configuration file, only admin actions require authentication; users can perform actions without logging in.

### User Setup

- Admin adds each user to the server.
- Admin sets an initial password and shares it with the user.
- On first login, the user **must change their password** via:

:::BlockQuote
POST /api/v5/auth/change-password
:::

:::hint{type="info"}
For a complete list of **API calls&#x20;**&#x66;or admins and users, refer to th&#x65;**&#x20;Swagger documentation.&#x20;**
:::

## Administrator Actions

:::BlockQuote
Authentication required: Yes
:::

### 1. User Mangement

- **Login:** POST /api/v5/auth/login
- **Add user:** POST /api/v5/auth/add-user
- **Remove user:** POST /api/v5/auth/remove-user

### 2. Administrators

***Online Licenses***

- **Add license:&#x20;**&#x50;OST /api/v5/license
- **Remove license:** DELETE /api/v5/license/\{id}

***Offline Licenses***

- **Generate offline activation request:&#x20;**&#x50;OST /api/v5/license/offline/activation/generate
- **Upload and activate license file:&#x20;**&#x50;OST /api/v5/license/offline/activation/upload
- **Generate offline deactivation request: &#x20;**&#x50;OST/api/v5/license/offline/deactivation/generate

***Air-Gapped Licenses***

- **Generate activation code:** POST /api/v5/license/airgap/generate
- **Upload license file & confirmation code:** POST /api/v5/license/airgap/activate
- **Generate deactivation code:** POST /api/v5/license/airgap/deactivate
- **Deactivate using confirmation code:** `POST /api/v5/license/airgap/activate`

## Bundle Management

- **Add bundle:** POST /api/v5/bundle
- **Remove bundle:** DELETE /api/v5/bundle/\{code}

:::hint{type="info"}
**Admins&#x20;**&#x63;an also **perform&#x20;**&#x61;ll actions that users are allowed to do.
:::

## User Actions

Authentication required:

- **Register/unregister to licenses:**

:::BlockQuote
POST /api/v5/license/\{id}/user/register
POST /api/v5/license/\{id}/user/unregister
:::

- **Register/release features:**

:::BlockQuote
POST /api/v5/license/\{id}/feature/register
POST /api/v5/license/\{id}/feature/release
:::

- **Add license or feature consumption:**

:::BlockQuote
POST /api/v5/license/\{id}/consumption/add
POST /api/v5/license/\{id}/consumption/feature/add
:::

## JWT Authentication

- Obtain a JWT token:

POST /api/v5/auth/login

- Include the JWT in the Authorization header for all authenticated requests:

Authorization: Bearer \<your-jwt-token>

### Example Floating License Flow

1. **Admin** creates a user.
2. **User** logs in and changes their password.
3. **User** logs in again to obtain a JWT.
4. **Admin** adds the license: POST /api/v5/license
5. **User** registers to the license: POST /api/v5/license/\{id}/register


[title] .NET/C#
[path] Frequently Asked Questions/SDK/

## Watchdogs

### If I set up the watchdog timer each time I run a command in my program is it using the same instance internally, recreating, or adding a completely new timer with duplicate callbacks?

 Setting up the watchdog stops the current instance (stops the timers), creates a new watchdog instance and starts it again.

### If I use the watchdog timer for floating and non-floating licenses, is there any need for me to call license.Check (online), since it seems like internally the timer is checking online and will throw all exceptions?

Watchdog, while running, will periodically call the Check method on the license object it was run on, regardless if the license is floating or not.

## license.Register and license.Check

### Do 'license.Register' and license.Check  have same functionality?

Yes, they are doing exactly the same thing


[title] SDK
[path] Frequently Asked Questions/

## Two devices same license feature

The customer is using both **PC1** an&#x64;**&#x20;PC2&#x20;**&#x77;ith the same license feature. **PC1** performs local consumption and then uses the `SyncConsumption` method to send the data to the server. These changes are visible within the portal.

However, when **PC2** calls the `SyncConsumption` method, the changes made by **PC1** are not visible in the localLicense file. To sync **PC2** with the server, the `CheckLicense` method should be used.

### Summary:

- If a feature is consumed, the `SyncConsumption` method will send the updated data to the server, resulting in changes to the localLicense file.
- If a feature is not consumed, the `SyncConsumption` method will neither send data to the server nor retrieve new data from the server.
- The only way to retrieve new information from the server is to call the `CheckLicense`method.


[title] Changelog
[path] Floating Server/Floating Server V2/

:::Changelog{title="v2.2.0 – December 24, 2025"}
::ChangelogItem{type="added" description="Hardware Key Support: FSv2 can be provisioned with a hardware key and can manage hardware-key compatible licenses and bundles."}

::ChangelogItem{type="added" description="Docker logging mode (logs to stdout)"}

::ChangelogItem{type="fixed" description="Bug fixes and minor improvements"}
:::

:::Changelog{title="v2.1.0 – November 26, 2025"}
::ChangelogItem{type="added" description="Offline refresh functionality"}

::ChangelogItem{type="added" description="Support for full SQLite database encryption using SQLCipher"}

::ChangelogItem{type="added" description="Optimized database performance, increasing concurrency capabilities"}

::ChangelogItem{type="added" description="Bundle license features visible in the UI"}

::ChangelogItem{type="fixed" description="Various bugs"}
:::

:::Changelog{title="v2.0.0 – October 6, 2025"}
::ChangelogItem{type="added" description="TLS support for PostgreSQL – Secure database connections are now supported"}

::ChangelogItem{type="added" description="Helper scripts – Added scripts to run PostgreSQL with TLS and Docker Compose for simplified setup"}

::ChangelogItem{type="added" description="Automatic config generation – Configuration files can now be generated directly from the LicenseSpring platform"}

::ChangelogItem{type="added" description="Simplified provisioning – Uses a single certificate for both server and client, reducing setup complexity"}

::ChangelogItem{type="fixed" description="Restricted the Floating Server to offline floating licenses only"}

::ChangelogItem{type="fixed" description="Various UI bugs and usability issues"}
:::

:::Changelog{title="v2.0.0-beta.2 – September 5, 2025"}
::ChangelogItem{type="added" description=" Restricted license activation to Offline Floating Licenses only"}

::ChangelogItem{type="added" description=" Official Docker image: licensespring/floating-server-v2:v2.0.0-beta.2"}
:::


[title] FastSpring
[path] Integrations/


[title] Management API Collection
[path] Common Scenarios/Glossary/Postman Collections/

### Management API Base URL

All Management API requests use the domain:
[**https://saas.licensespring.com&#xA;**](https://saas.licensespring.com)Do **not** use [**https://api.licensespring.com**](https://api.licensespring.com) for Management API requests.
&#x20;That domain is reserved for the License API.

### Required Authentication Key

The Management API requires the following key:

- managementApiKey&#x20;

The keys below **are not valid** for the Management API:

- apiKey&#x20;
- sharedKey&#x20;

These keys apply exclusively to the License API and cannot be used for Management API authentication.

These settings are accessible in the LicenseSpring development environment, which must be selected in Postman.


![Select environment](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/GIb13Ty2d-Yd8N7L6tKVG_image.png "Select environment")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/3ZXTY1N3JPQC34WhMMHrG_image.png)

## Management API variables

The Management API collection uses several environment variables that are automatically populated by running the corresponding List requests inside each folder. These variables allow PATCH, DELETE, and GET-by-ID operations to work without manual input.

### **Automatically populated variables**

When you run the first request in a folder (e.g., *List Customers*, *List Products*, *List Licenses*), the script extracts the ID of the **first** returned item and stores it in the environment:

| Variable          | Description                                                   |
| ----------------- | ------------------------------------------------------------- |
| `customer_id`     | Set by running **GET Customers**                              |
| `product_id`      | Set by running **GET Products**                               |
| `license_id`      | Set by running **GET Licenses**                               |
| `labels_id`       | Set by running **GET Labels**                                 |
| `features_id`     | Set by running the corresponding **List Features** request    |
| `user_id`         | Set by running **List Users**                                 |
| `order_id`        | Set by running **List Orders**                                |
| `accounts_id`     | Set by running **List Accounts**                              |
| `activation_id`   | Set by running **List Activations**                           |
| `installation_id` | Set by running **List Installations**                         |
| `…`               | All other variables are set by their respective List requests |

If a List request returns an empty array, it means no resources exist yet.
&#x20;You can either:

- Create the resource in the LicenseSpring UI, **or**&#x20;
- Use the POST request provided in the same folder.

## **How the Management API Collection Works**

Each folder in the Management API collection follows a consistent workflow:

1. **Run the List request**&#x20;
   - Retrieves all resources of that type&#x20;
   - Automatically stores the ID of the first item in the environment variable&#x20;
   - Example: GET Products → sets \{\{product\_id}}&#x20;
2. **Run other requests (Show, Patch, Delete, etc.)**
   &#x20;These requests automatically read the ID from the environment variable&#x20;
   - No need to manually replace values&#x20;
   - Simplifies testing and minimizes errors

### **Why the first resource in the list?**

For convenience and automation.
&#x20;If you want to target a different resource, you can simply change the environment variable manually (see below).

## **Manual variable adjustment (optional)**

If you prefer to use an ID other than the automatically selected one, you can manually set a value in the environment:

1. Copy the ID from the UI (e.g., from https\://saas.licensespring.com/orders/order\_id/license\_\<ID>).&#x20;
2. Paste it into the matching environment variable (e.g., license\_id).&#x20;
3. Run any request in the folder — it will now use your manually selected ID.

![Add your license\_id](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/FHww2u0a6u088nZeCTiKI_image.png "Add your license_id")

Or set it up from using **POST/create request** inside request body:



![Add value to existing variable](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/TvL9D8K47BPtRfkC6AUIO_image.png "Add value to existing variable")

- **Important:** script will override your **product\_id** if you run again list request in that folder, please delete/remove the post response script as shown on picture:


![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/oxpEDQcpUQ4TkBHPZ2xDH_image.png "Script setting 1st item")



## **OAuth Folders inside the Management API Collection**

Some folders include OAuth-based Management API endpoints.
&#x20;These require:

- license\_id, or&#x20;
- customer\_id, or&#x20;
- customer\_account\_code&#x20;

These variables are populated automatically by running the corresponding *List* requests.
&#x20;If you want OAuth requests to target different resources, update these variables manually.

If your organization has enabled OAuth scoping (customer-level, license-level, or account-level), the IDs must match the scope assigned on your LicenseSpring platform.

## **Example workflow&#x20;**

**Products Folder Example:**

1. Run **GET Products**
   &#x20;→ sets \{\{product\_id}}&#x20;
2. Run **GET Product (Show)**
   &#x20;→ uses \{\{product\_id}}&#x20;
3. Run **PATCH Product**
   &#x20;→ updates the same product&#x20;
4. Run **DELETE Product**
   &#x20;→ deletes the same resource&#x20;

Every folder works the same way.

## **Common Issues**

### &#x20;1. 404 Not Found

You ran PATCH/DELETE but no ID was set.
&#x20;Run the folder’s List request first.

### &#x20;2. 401 Unauthorized

Your managementApiKey is missing or has a trailing space.

### &#x20;3. Invalid URL

Your **management api url&#x20;**&#x68;as a trailing slash or extra space.

**NOTE:** Always ensure there are **no extra spaces** in any environment variable.

[title] User portal changelog
[path] Changelog/

### February 4, 2026, v3.244.0

- Floating Feature borrow and release functionality

### January 19, 2026, v3.243.0

- Implemented Custom Fields UX Enhancements
  - Implemented UI distinction between License and Product Custom Fields
  - Implemented reseting license custom fields to product custom field value
  - Added explanatory labels for setting license custom fields and overriding product default custom fields

### January 12, 2026, v3.241.0

- Fixed bundle Order creation

:::Changelog{title="16.12.2025."}
::ChangelogItem{type="added" description="Bulk reset for license devices"}

::ChangelogItem{type="added" description="Actions: editing customers, editing licenses, editing license custom fields, editing license product features"}
:::

:::Changelog{title="04.12.2025."}
::ChangelogItem{type="fixed" description="Issue with bundle licenses, assign user to license and edit assigned user functionality"}

::ChangelogItem{type="added" description="Search filters: filter by license ID, filter by license Note"}
:::

:::Changelog{title="11.04.2025."}
::ChangelogItem{type="fixed" description="Properly handle reset for devices on bundle licenses"}
:::

:::Changelog{title="05.03.2025."}
::ChangelogItem{type="added" description="Added Max License users column on license list"}

::ChangelogItem{type="fixed" description="Fixed getRedirectUri function"}

::ChangelogItem{type="fixed" description="Properly handle useAPI hook to prevent infinite loops"}

::ChangelogItem{type="fixed" description="Enabled sorting on license devices tab table"}
:::


[title] Vendor Platform
[path] Common Scenarios/Glossary/

## Customer

Basic [**Customer**](docId\:apO4EHanqk86ZfCknvmnK) information is stored within the LicenseSpring platform as customer profiles. These profiles contain essential details about customers, such as their name and email address. By having this information stored in the platform, it becomes convenient to search for orders of licenses associated with a specific customer.

## Customer Accounts

[**/customer-accounts/**](docId\:yKjjclSyU-32gmtQDI8uH) are a way to group multiple business units of an organization within the LicenseSpring platform. It allows for the convenient organization and management of customers based on specific criteria or attributes.

## Customer Import

The system allows a requesting manager to import customers from a CSV file if they have the necessary access permissions.

For more information, see our documentation on how to [**Import Customers from CSV**](docId\:o-XpEnl-n8N8dwqwrE8pF).

## Customer Labels

[**/customerclabels/**](docId:0Z_cODJf843U_x6RkZwfu) are tags or labels that can be assigned to customers or organizations to categorize and group them based on specific criteria or attributes.

## Customer/Product/License Metadata

Customer metadata provides insights into individual customers, product metadata provides details about specific software products, and license metadata provides information about the characteristics and status of software licenses.

## Customer Reference

A customer reference is contact information or testimonials from existing customers who have successfully implemented and used the software. These references serve as a way for potential customers to gain insights into the experiences and satisfaction levels of current customers.

## Disabling a License

[**Disable License**](docId\:NgvefcAwUWb-7l3wA1oZs) revokes all entitlements associated with the specific key. For example, if an end user requests a refund or decides to discontinue using an application, the software publisher can issue a refund and disable the license key, preventing further access to the full version of the application.



![Disabling a License](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/NAmJk1lG0XEAF1OlWXCwn_image.png "Disabling a License")

## License

A license is a legal agreement or permission granted by a software vendor or provider that allows individuals or organizations to use a specific software product or service. It establishes the terms and conditions under which the software can be utilized, including usage rights, limitations, and any associated entitlements.

Within LicenseSpring, licenses are closely linked to orders. An order refers to a transaction or purchase made within the LicenseSpring system, and each license is associated with a specific order. This means that multiple licenses can be issued under the same order, allowing for efficient management and administration of licenses.

## License Export

If a requesting manager has the appropriate access permissions, they can [**Export Licenses History**](docId\:cjpUJNS7WTsKxkTXYsNTS) data to a CSV file.

## License Import

The system allows a requesting manager to [**Import Licenses From CSV**](docId\:P8KUpKwpexBgzJC2W3Bht) if they have the necessary access permissions.

## License Manager Permissions

License manager permissions refer to the specific rights and privileges granted to individuals or roles responsible for managing licenses within a software licensing system. These permissions determine the actions that license managers can perform and the level of control they have over license-related activities.&#x20;

To see a list of permissions, see: [**The License Manager**](docId\:RnanVALD4nqH_ml4Y0o0J).



![Assigning Permissions](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/bTOarK5R3vYaWHrKXogMK_image.png "Assigning Permissions")

## License Status

License status refers to the current state or condition of a license within a software licensing system. It indicates whether a license is active, inactive, expired, revoked, or in any other predefined state that determines its validity and usage rights.&#x20;

To see a list of potential license statuses, see: [**License Types**](docId\:xHxttCVj7gs6qeAqu7Cua).

## License Usage Report

A license usage report provides comprehensive information about the utilization of licenses within a specified timeframe. This report presents data on license activations, deactivations, and other relevant metrics that help assess the usage patterns and trends.



![Usage Report Page](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/0A0fC8gBHyxtjHLSVQzBk_image.png "Usage Report Page")

## Linked Accounts

Linked accounts refer to the capability of associating multiple user accounts or entities together within the software system. This feature allows for centralized management and control of licenses across connected accounts.

## Notification Events

[**Email Notifications**](docId\:gKXhf0Gct6fNZVgLENN76) are triggered when specific conditions are met. Users have the ability to define notification policies, modify or remove them, monitor notification history, and customize email templates for each event. (For a comprehensive list of available events, refer to the documentation on notifications.)

## Order

An [**Order**](docId\:DfMlvcgLu4fHrne1qkNFh) refers to a transaction or purchase made within the LicenseSpring system. It is associated with a specific order number that serves as a unique identifier. When utilizing an e-commerce platform, the order ID is typically provided upon the completion of a transaction. In LicenseSpring, every license is linked to an order, and multiple licenses can be issued under the same order. The order serves as a container for organizing and managing licenses, allowing for easy tracking and administration of license-related activities.

## Platform Audit Log

The [**Audit Log**](docId\:DNw8-FOmIRkNM7Y9v_YEX) is a useful table to keep track of all essential actions performed within an account and who performed them.



![Audit Log](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/_725o7LGD6I2eJheWz_pH_image.png "Audit Log")

## Platform Permissions

[**Roles/Permissions/User Labels**](docId:9UhmGnrQIiLFhhkTzNIS8) refer to the customizable rights and privileges that can be assigned to platform users within a software platform or management system. These permissions determine the actions and functionalities that platform users are allowed to access and perform within the platform.

## Platform Users

List of users that have access to the platform account.

## Resetting a License

[**Reset License**](docId\:vvXMCUyxpfYE7YvdaXUQp) revokes all existing entitlements from any previously authorized computers and restores the license key to its pre-activation state. This process erases any linked hardware ID, and the validity and maintenance periods are reassigned upon the next activation of the license key. Resetting a license is useful when a user changes computers, for instance.

## SSO Settings

The configuration and customization options for implementing [**Single Sign On (SSO)**](docId\:kSLObq_GFMuulxYf7JFji) authentication in an application or system. SSO allows users to authenticate once with their credentials and gain access to multiple systems or applications without the need to log in separately for each one.




[title] HubSpot Integration User Documentation
[path] Integrations/HubSpot/

# Introduction

The following article will take you through our HubSpot integration and all its current functionalities.

The current integration supports **Company** and **Contact** **HubSpot CRM** **objects**, and the integration is able to be set up on those objects **View pages.**

# Prerequisites

This documentation assumes that you have a **HubSpot** and a **LicenseSpring** instance setup beforehand.

We assume that you have already gone through the **HubSpot Integration Installation Setup&#x20;**&#x64;ocument and have installed and setup the integration application in your HubSpot instance.

We assume that you have the necessary **permissions&#x20;**&#x69;n your HubSpot instance to use the installed integration.

# HubSpot Contacts / LicenseSpring Customers

If you have installed the app correctly + added it to your **contact** **view page,&#x20;**&#x20;you will be able to see the following window once you open up a contact (any contact) that you have in your HubSpot instance. The same applies from **Companies**.

:::hint{type="info"}
Depending on your page setup, your contact page might have slightly different options available or positioning of the integrations UI.
:::

:::hint{type="info"}
If you have use cases where you need the integration to be able to support not only Contacts and Companies but for example Leads or any other CRM objects, [**let us know**](https://licensespring.zendesk.com/hc/en-us/requests/new), and we will implement the needed support.
:::

![Contact View Page in HubSpot.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/CdGBY41uszsX3RgBvMPAw_screenshot-2024-12-10-at-095631.png "Contact View Page in HubSpot.")

:::hint{type="info"}
Initially your contact information won't be immediately transfered to your LicenseSpring instance. The information gets transferred to LicenseSpring once you create your first license on that contact.
:::

# Creating Licenses in HubSpot

Once you click on the **Create License** button, you will need to select a product on which you want the order/licenses to be created on. The products that you can pick are directly pulled from your LicenseSpring instance.

![License Creation Page.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/mkhh4W0F5HSbwHIxdTKow_screenshot-2024-12-10-at-095715.png "License Creation Page.")

We'll select the product named **License Software** for this documentation.

![Selecting Product for License.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/st0Zc5KqN8c03dgC-MAmA_screenshot-2024-12-13-at-144011.png "Selecting Product for License.")



This will enable us to pick a **License Policy** from the **Product** with which we'll create an order/license. Same as the products, the **License** **Policies** are pulled from your LicenseSpring instance.

## License Policies&#x20;

If you have the need to create more **License Policies**, you can go to your LicenseSpring instance and create additional ones and they will be available in the drop down after a page refresh.

![Selecting License Policy for the License.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/pX_0yj7s7zDkP597DYm-y_screenshot-2024-12-13-at-144549.png "Selecting License Policy for the License.")

![Adjusting Types of License Policies.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Pionxmp00WYF7gLkF7CnD_screenshot-2024-12-13-at-144531.png "Adjusting Types of License Policies.")

Depending on the license policy you pick, the information on the left side of the window will change, and show you details about that license policy and also additional options/input fields will be show below. We'll pick a time-limited license policy for this demo and change the quantity of the licenses to 5.

![Adjusting Time-Limited Values for the License.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/qcLkTaY5INcG4LNFI5CZB_screenshot-2024-12-13-at-145001.png "Adjusting Time-Limited Values for the License.")

:::hint{type="warning"}
If your **Contacts Company** does not have a name set, you might get the following error "Company name can't be empty". Please enter a name to avoid this error.

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/-FXVrVtwD_N8rl_8Pg4G2_screenshot-2024-12-13-at-150032.png" signedSrc size="46" width="372" height="56" position="center" caption="&#x22;Company name can't be empty&#x22; error." alt="&#x22;Company name can't be empty&#x22; error." darkWidth="372" darkHeight="56"}
:::

After clicking on the **Create Order** button, and a small loading time, we are back on the contacts page where we can see the 5 new licenses that got created

![Created Licenses from order.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/0Y8f2PHGoaBVktzmltbuj_screenshot-2024-12-13-at-150405.png "Created Licenses from order.")

## Connecting Contacts to LicenseSpring Customers

Initially you will not be able to see any Licenses on Contacts in our apps table (even aready created old Licenses from the LicenseSpring Platfrom). This is becuase the contact is not yet connected to to a LicenseSpring customer and our app will throw a warning that no connection is currently in place.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Rn6PRu5NVLKSPuCq_Jnee_screenshot-2025-11-28-at-141404.png)

The warrning mentions that there are currently 2 ways to connect a Contact to a LicenseSpring Customer.&#x20;

### New Contact That Does Not Exist in LicenseSpring

The first way is really simple, you just need to create a new license though our app and after you will be able to see all the old licenses from the LicenseSpring platfom together with the newly created Licenses. This will also create a new customer in LicenseSpring with the same email as the contact in your HubSpot instance.

### Connecting Already Existing Customer&#x20;

If your customer already existing in the LicenseSpring platfom and you want to see their old licenses in HubSpot you will need to follow the next steps.

You will have the option in the warrning message to click on the "Connect customer" buttom. Clicking on it will open up a panel in which you can pick which customer to connect, the dropdown will show only similar customer from LicenseSpring.

::Image[]{src="https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/DClJLCq7vFlHBpinWrQyF_screenshot-2025-11-28-at-142106.png" signedSrc size="54" width="880" height="820" position="center" caption darkWidth="880" darkHeight="820"}

Once you click on the "Connect" button you will be able to see old licenses.

:::hint{type="danger"}
Customer data in LicenseSpring will be overwritten with data from HubSpot
:::

### Changing Already Connected Contact and Customer

If you already have a connection in place and you need to change it to a different LicenseSpring customer you can do so by clicking on the "Connection" button.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/NAKAdEAweo5UuDsXJYZog_screenshot-2025-11-28-at-142633.png)

This will open the following panel

::Image[]{src="https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/Rnap3Gs8EI1MgQ4oXOqmK_screenshot-2025-11-28-at-142249.png" signedSrc size="58" width="862" height="1082" position="center" caption darkWidth="862" darkHeight="1082"}

Using this panel you can then connect of diconnect customers from your contacts.

# License Details / LicenseSpring Link

Every license has its **License ID** shown in the table of **Licenses**, and if we click on it, a side panel will pop up and show all the necessary details of the license with the additional link that can take you to your license in your LicenseSpring instance .

![License ID of Individual Licenses](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/hvPVU7EufVxcYgI0U6TUA_screenshot-2024-12-13-at-151125.png "License ID of Individual Licenses")

![Link to See License in LicenseSpring Instance.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/DH1wz7OrT14XVVXZA4gbU_screenshot-2024-12-13-at-150533.png "Link to See License in LicenseSpring Instance.")

# Updating Licenses in HubSpot

Once the **contact** has its **licenses** created, you have the ability to update some **license** **parameters** (depending on the license type you created).

If we click on the **Update&#x20;**&#x62;utton on the right side of the license table, we are show all the fields that we can update on a license for that certain type.

![Updating Existing License](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/CakOcY5VirmmudkadAXMJ_screenshot-2024-12-13-at-151706.png "Updating Existing License")

![Update License Page.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Z50-ctJsxzQ9lKkEWxFfr_screenshot-2024-12-13-at-152002.png "Update License Page.")

Once you're happy with your changes (you will be shown below the **Update&#x20;**&#x62;utton all the fields you changed) you can click on the **Update fields** that is located in the lower right corner of the screen (some users on smaller screens will have to scroll down).

![Changed Fields View.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/SmRx2pe622Gt0DVv4j_Qb_screenshot-2024-12-13-at-152300.png "Changed Fields View.")

## Product Features

You are able to add or remove **Product** **Features** when your're updating your license.

![Adding Product Features.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/c6Agoqp1WGNm4UcDWpFFC_screenshot-2024-12-13-at-151414.png "Adding Product Features.")

To do so, you will need to scroll down the update pop up window and click on the **Add** button which will open a pop up section on which you can by clicking/selecting the feature you like in the dropdown add **Product Features** to the license&#x20;

![Selecting Features to Add.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ZNKnsSts31bEa5Q-alU5C_screenshot-2024-12-13-at-152729.png "Selecting Features to Add.")

![Selected Features.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Yp8zoRhlYOl92Yqs89T7M_screenshot-2024-12-13-at-152911.png "Selected Features.")

Once you're done you need to click on the **Add features** button, and this will add the product feature to the respective license.

![View of Added Features.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/T6B8XUB0Vf1elz44LMqiU_screenshot-2024-12-13-at-152932.png "View of Added Features.")

You can also remove the features by clicking on the delete button in the right side of the features table.

![Removing License Features.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/nbBrfnqBn8CbQSJwIOSwM_screenshot-2024-12-13-at-153221.png "Removing License Features.")

## Custom Fields

When updating your licenses, in the update window there is a section for custom fields if you scroll to the bottom of the page.

![Custom Fields Section.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/RsVm7DM2_K8s5wUiDCgkJ_screenshot-2024-12-13-at-153412.png "Custom Fields Section.")

:::hint{type="warning"}
If your product does not have custom features you will first need to go to your LicenseSpring instance, create them on the product, add them to a **license policy** and then come back here and refresh the page and create the **Order&#x20;**&#x61;gain.
:::

You are able to edit the custom fields value by clicking on the **Edit** button next to the custom field that you wish to edit.&#x20;

![Editing Custom Fields.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/BQA-uEt2apPPiwBWct7gm_screenshot-2024-12-13-at-153846.png "Editing Custom Fields.")

This will open up an another pup up window on which once you're happy with your edit, can click on the  **Update custom field** button to save the changes.

![Changing Custom Field Value.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/FeF712nV0Ap9QBpQQ6KRX_screenshot-2024-12-13-at-153903.png "Changing Custom Field Value.")

# HubSpot Companies / LicenseSpring Accounts

Much in the same way as contacts, companies connect to LicenseSpring customer accounts.

Once you create a License on a company, in LicenseSpring a new Customer Account will be created and on that account the License you created will be shown.

![Company Object View.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/DNlz3c8j3vvMXZnKhQnuF_screenshot-2024-12-13-at-154541.png "Company Object View.")

## Creating/Updating Licenses Through Companies

Same as with **Contacts, Companies&#x20;**&#x61;lso have a button to create licenses. The flow follows the same creation process.

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/EgSitWm02gqB6vxiVuhyp_screenshot-2025-11-28-at-144915.png)

And also by scrolling to the left and finding the "Update" button in the License table you will able to update a existing License that is tied to a Company / Customer account.

::Image[]{src="https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/3JdIVHN6qNYM7LM5No7uG_screenshot-2025-11-28-at-145129.png" signedSrc size="98" width="2090" height="1542" position="center" caption darkWidth="2090" darkHeight="1542"}

# Automatic License and Customer Creation / Workflows

### Common Workflow Use Case

Lets say that you already have a HubSpot form in place where your users are inputing their information (like their email on your website) and you want to automatically assign them a trial license and you want the account to be created as a LicenseSpring customer, you can do so by using the "action" detailed below.

## Workflow Action

The integraiton provides the ability to automate license creation by using HubSpot Workflows. You can do so by going to you workflow ("Automation" -> "Workflows" -> Pick your workflow) and when selecting to add a new action in the panel that opens up on the left side you will be able to pick our custom action "Create LicenseSpring License" in the "Integrated apps" section under "LiceneSpring Integration".

::Image[]{src="https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/kg-GLkeRVjMgeRjcakv7n_screenshot-2025-11-28-at-145654.png" signedSrc size="70" width="908" height="1288" position="center" caption darkWidth="908" darkHeight="1288"}

Once chosen you will need to set the LS Product and the LicensePolicy.&#x20;

::Image[]{src="https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/OjjdXzMmk5k7Hk_u0Gs2r_screenshot-2025-11-28-at-150220.png" signedSrc size="56" width="910" height="902" position="center" caption darkWidth="910" darkHeight="902"}

## Forwarding Information to the Workflow Action

If you click on the "Add Customer to the order" checkbox addtional fields will open up.

::Image[]{src="https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/4klwcIsmCR3QuJ1ubF4Dh_screenshot-2025-11-28-at-150509.png" signedSrc size="50" width="910" height="1358" position="center" caption darkWidth="910" darkHeight="1358"}

In each of the fields you will be able to forward information from the objects from other actions in your workflow.&#x20;

::Image[]{src="https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/Lru3NTncj3Sc4R5_BuQ8n_screenshot-2025-11-28-at-150631.png" signedSrc size="76" width="1626" height="1356" position="center" caption darkWidth="1626" darkHeight="1356"}

:::hint{type="info"}
You can use the LicenseSpring "Action" in multiple Workflows in multiple different use cases. If you have a use case that can not be covered by the current LicenseSpring "Action", let us know by sending our support team an email (link below) and we'll try to expand or add an aditional action if possible.
:::

# HubSpot Deals cards

To view licenses for a contact or company associated with a deal, add the **Deal Contact Licenses** or **Deal Company Licenses** card to the **Deals** view. This allows you to verify if any associated records have licenses assigned to them.

These cards are added to the view in the same way as any other card. Please refer to [**HubSpot Integration Installation Guide**](docId\:PetX4rX6Xy8uUXrBbJWeB) for detailed instructions.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Ry3KI1E_TiOa9TDDV1wUg_image.png)

:::hint{type="warning"}
These cards display a maximum of **6** licenses for each Contact and **10** licenses for each Company. To view the full list of licenses for a specific record, please navigate to that Contact or Company's record page.
:::

# Additional Features and Support Requests

If you have use cases where you wish that aditional HubSpot objects are supported in our integration or additional LicenseSpring features are available in the integration inside HubSpot, let us know by [**contacting our development team**](https://licensespring.zendesk.com/hc/en-us/requests/new).

If for some reason the integration is not behaving as it is documented here, let us know by [**contacting our support team**](https://licensespring.zendesk.com/hc/en-us/requests/new).

[title] Integrations
[path] /

Elevate your licensing operations by connecting LicenseSpring from leading platforms in the industry.

## Salesforce

Enhance your CRM capabilities by integrating LicenseSpring with [**Salesforce**](docId:1TJgk6xKroiN2_FLsKtVv). Salesforce enables you to efficiently manage customer relationships and licensing data while gaining valuable insights to boost your revenue.

## FastSpring

Experience efficiency and simplicity with LicenseSpring's [**FastSpring**](docId:9Q87CnXkunvQBhKEBpR-r) integration. Automate license provisioning, streamline order processing, and manage subscriptions.

## Stripe

Take control of your revenue management. Connect LicenseSpring to [**Stripe**](docId:-ny0MceSD689_M1OPs5YS) for efficient handling of payments, subscription billing, and secure financial transactions.

## Shopify

Optimize your e-commerce licensing with LicenseSpring's [**Shopify**](docId\:KMIawJSvFgKP4vEy4-cYJ) integration. Easily manage licenses within your Shopify store, simplifying the monetization of your products and services.

## **Why Choose LicenseSpring Integrations?**

- **Ease of Use**: Our integrations are designed for simplicity, ensuring a smooth setup process.
- **Efficiency**: Simplify your licensing processes, improve productivity, and reduce manual work.
- **Scalability**: LicenseSpring integrations are adaptable, catering to startups and enterprises alike.
- **Reliability**: Trust in a secure and well-maintained integration to keep your licensing operations running smoothly.


[title] License Configuration
[path] Common Scenarios/Glossary/

## **Air Gap Licensing**

[**Air-Gapped License Activation**](docId\:UFo9u_RePM5NOV_0qBySZ) follows a similar concept to offline activation. The key distinction is that, in air-gapped environments, file exchange is not feasible. Therefore, the activation process relies on exchanging strings instead of files.



![Air-Gapped Keys](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/6YP6NZedjXPc7K1Ze6ZHm_image.png "Air-Gapped Keys")

## **Concurrent License**

Concurrent license, same as the [**Floating Licenses**](docId:4aUNyPIaL8I2te4NypPx7) model, allows multiple users to utilize the license simultaneously. For example, with a shared license key among 100 machines, up to 10 machines can concurrently run the binary using the same license. The number of machines sharing the license can be set to unlimited.

## **Consumption-Based/Metered Usage License**

A [**consumption-based or metered usage**](https://licensespring.com/software-licensing/metered-licensing/) license model allows software vendors to implement a pay-per-use or metered approach for their end-users. This model is similar to "credits" in an arcade game, processing cycles in a CGI rendering farm, or generating a specific number of reports, where the usage is measured and billed accordingly.



![Configuring A Consmption-Based License](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Q6ioOOR-mELOtZXophiyj_image.png "Configuring A Consmption-Based License")

## **Floating Cloud License**

A [**Cloud Concurrent Licensing**](docId:4z7qU0WF3SeScJDnw76q-) enables multiple users or computers to share the same license, but the application can only run a single instance. The specific computers that share the license are defined. This licensing model can be cost-effective compared to purchasing individual licenses for each user or seat.

## **Floating License Server**

A [**Floating Server**](docId\:sS5gX73i5CjOrDgK1Ed8I) is designed for implementations where licenses are issued for on-premise servers, and client devices do not require an internet connection to request or release licenses from the server. This setup allows for efficient management and distribution of licenses within a local network.

## **Floating Max Simultaneous Users**

The Floating Max Simultaneous Users represents the maximum number of machines that can concurrently use a floating license. It is important to note that Max Simultaneous Users and Max Activations are not the same. Max Activations refers to the number of machines that are node-locked to the license. A license must be activated on a device before it can be checked out. Therefore, the number of Simultaneous Users should be less than or equal to the Max Activations configured for the license.

## **Floating Timeout Period**

The Floating Timeout Period refers to the duration in minutes that the license app needs to ping the LicenseSpring server to maintain an active license. If the app fails to ping the server before the timeout period elapses, the license will be released from that app, making it available for other users. To modify the Floating Timeout Period for a configured product, navigate to the product settings, click on "Edit Product," and adjust the License Configuration accordingly.

## **Key-Based License**

[**Activate a Key-Based License**](docId\:fF0ezEWc-EOi3l8NypEh6) is a model in which software usage authorization and validation are managed through the use of a license key.

## **License Borrowing**

License borrowing allows users to temporarily "check out" a floating license from the license server for a specified duration. During the borrowing period, the license can be used without requiring communication with the license server. Once the borrowing period expires or the license is manually checked in, it is returned to the pool of available floating slots. This feature provides flexibility in utilizing licenses when internet connectivity is intermittent or not available.



![Borrowed Device Details](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/dK7j8CmDjc_FALbQLSz1o_image.png "Borrowed Device Details")

## **License Custom Fields**

[**Custom Fields**](docId\:QwHqkQN4JZuGAFmy1GehV) are key-value pairs that enable software developers to define and push custom information to end-users at the license level. These fields provide a flexible way to include additional personalized or specific information associated with the license.&#x20;

## **License Expiration**

A license key is considered expired when it is no longer valid. Typically, this entails the application rolling back any entitlements associated with the license key, transitioning from a commercial state to a trial state.

## **License Features**

[**Features**](docId\:pTsdhUAr9YJhGPVbKxb4o) refer to the ability to enable or disable specific features or functionalities within an application without requiring separate binaries or extensive code modifications. This allows software developers to control the availability of features based on the license entitlements.



![License Feature List](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/GuQ-nM7bnN3tFmS4fgyI1_image.png "License Feature List")

### **Activation Features**

The activation feature is a straightforward functionality present in a license. It can be either enabled or disabled, indicating whether the license supports activation or not.

### **Consumption Features**

Consumption feature licensing enables metered usage of a specific feature within an application. This licensing model proves useful when the vendor intends to restrict the number of times a particular function is executed or a specific report is generated. It allows for precise measurement and control over the usage of the feature based on predefined thresholds or limits.

### **Feature Expiry Date**

Product features can have a time limitation. This means that the expiry\_date field on license product features can be set as a specific date (with the default value being null). This expiry\_date is validated during license checks, license activations, offline license activations, and add\_feature\_consumption processes. Any product features with an expiry\_date in the past or on the current date (according to UTC time) will be automatically removed from the license.

### **Reset Feature Consumption**

Resets the consumption count on a license feature, setting it back to zero.

## **License Note**

[**License Note**](docId\:cEZcfD5Sf0Y0INMKkqtx7) are additional information or comments that can be included by license managers in the back-end system for individual licenses.&#x20;



![Edit License Note](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ovw9XxOWo5QO8IlPB6gcb_image.png "Edit License Note")

## **License Policy**

A [**License Policies**](docId\:BUG-ZHe_gTAr26CDeQlTK) is defined on a product and acts as a template for license entitlements. Every product must always have at least 1 license policy, which also acts as a default. When issuing licenses, you would just select the appropriate license policy or customize from a given license policy.

## **Maintenance Period**

The [**Maintenance Period**](docId\:Modljq4cp5uboMxrRQxbK) is the duration during which the end user is eligible for software updates after activating a license key. While the maintenance period is active, the software publisher can configure the SDK to check for and push the latest application updates to the user. Once the maintenance period expires, users can still access and activate updates released prior to the expiration. The maintenance period can be set to never expire.

## **Max Activations**

Max Activations refers to the maximum number of distinct devices that can be activated against a license.

More information on activations can be found at [**Activations & Device Transfers**](docId\:ElqxIF31yMc7CksUf366c).



![Max and Total Activations ](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/VsqEoYRoIE5vCtVlT7mtC_image.png "Max and Total Activations ")

## **Max Consumption License / Feature Overages**

Overages refers to the allowance given by the software vendor for the license (or license feature) to exceed the maximum value set for consumptions. If overages are permitted, the vendor can specify a specific value by which the license (or license feature) can exceed the maximum consumptions limit. However, if overages are not allowed, the Max Overages value is set to 0, indicating that it cannot exceed the defined maximum consumptions.

## **Max Consumptions**

Max Consumption refers to the predefined limit that determines the maximum usage allowed for a license. It represents the highest threshold or cap set for utilizing the licensed features or resources. The Max Consumption value specifies the maximum number of times or quantity that a particular functionality or resource can be accessed or utilized within the license terms.

## **Node-Locking**

[**Node-locking**](https://licensespring.com/software-licensing/node-locking/) a license involves specifying the number and type of devices or computers that are authorized to bind to and use a particular software license. This process generates a unique [**Python Hardware (Device) IDs**](docId\:ORDujMleQE_0SSSxxa3bQ) based on the device's specifications using the SDK. The license becomes tied to these IDs, preventing unauthorized usage or sharing. Each license file is designed for activation on a specific device, ensuring it cannot be used on unintended devices.

## **Offline Licensing**

Offline licensing refers to the mechanism developed to enable the activation and deactivation of licenses in an environment where some computers do not have an active internet connection or are behind firewalls that prevent online activation.

### **Offline Activations**

[**Offline License Activation**](docId\:FEyF5UIc8A7RvjQ9LCz3g) are the initial step in offline licensing. It involves verifying the software license and authorizing its use on a specific device or system. Instead of connecting to a license server over the internet, offline activations typically involve generating a unique activation key or file that is tied to the hardware or software configuration of the device. This key is used to activate the software without requiring an internet connection.

### **Offline License Checks**

Offline license checks are performed to validate the license status of the software on the user's device. These checks ensure that the software is being used within the terms and conditions defined by the vendor. To perform offline license checks, the software may periodically scan the device or specific license files to verify the validity of the license. It may also compare the current system configuration with the authorized parameters to prevent unauthorized usage.

### **Offline License Refresh**

Offline license refresh is used when a license has already been activated on an offline device, but there is a need to modify the license entitlements, such as adding new license features. This process synchronizes the local license with the platform, ensuring that the latest entitlements are applied.

![Downloading License Refresh File](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/U5yafQA33Mrwvnl649zAw_image.png "Downloading License Refresh File")

## **Perpetual License**

A perpetual software license is a commercial licensing model that grants end-users the right to use an application indefinitely, without any time restrictions. Once obtained, the license remains valid without the need for renewals or expiration dates.

More information about perpetual licenses can be found on our [**License Types**](docId\:xHxttCVj7gs6qeAqu7Cua) page.

## **Prevent Virtual Machine**

Device fingerprinting becomes irrelevant on virtual machines as they often share the same machine profile, resulting in identical hardwareID computations across instances. Consequently, the configuration of "max activation" becomes inconsequential. To address this scenario, app developers have two alternatives: either utilize floating licenses or implement measures to prevent their software from running on virtual machines.&#x20;

## **Reset Consumption**

[**Reset Consumptions on License**](docId\:JQkXl4fffZaZH9YmixyID) is a functionality that automatically restores the available number of license (or license feature) uses to the predefined value specified in the "Max Consumption" field at regular intervals. This reset can occur on a daily, weekly, monthly, or annual basis, depending on the chosen reset period. By resetting the consumption count, users are granted a renewed allocation of usage for the specified time period, ensuring fair and controlled access to the licensed features or resources.

## **Subscription License**

A subscription license is a type of license where the validity is dependent on the status of an active subscription. As long as the buyer maintains an active subscription, the license remains valid, granting them the rights and access to the software or service. If the subscription is not renewed or expires, the license may no longer be valid, and the user's access to the software or service may be restricted.

More information about subcscription licenses can be found on our [**License Types**](docId\:xHxttCVj7gs6qeAqu7Cua) page.

## **Time-Limited License**

A time-limited license is a type of license that has a predefined expiration date. After the specified date, the license ceases to function. The validity period of a time-limited license can be extended by the Independent Software Vendor (ISV) if required.

More information about time-limited licenses can be found on our [**License Types**](docId\:xHxttCVj7gs6qeAqu7Cua) page.

## **Times Activated**

A license begins with 0 activations and increases by 1 each time it is activated. When a device is deactivated from the license, the activation count decreases by 1. The total activations should never exceed the maximum allowed activations.

For more information, visit our documentation on [**Activations & Device Transfers**](docId\:ElqxIF31yMc7CksUf366c).

## **Total Consumptions**

Total Consumptions refers to the count of consumptions that the end-user has already utilized. It is important to ensure that this value remains within the limit defined by the sum of Max Consumptions and Max Overages.

## **Trial License**

[**Trial Licenses**](docId\:yTf2lw7VQRYhv_uM2OqQH) are an alternative, expiring license type that exists within the LicenseSpring SDK. Trial licenses provide LicenseSpring’s customers the opportunity to tailor the state of their application for trial users.



![Trial License Configuration](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/0w7kZsp9-pk6W1D74EU6q_image.png "Trial License Configuration")

## **User-Based License**

[**User-based licensing**](https://licensespring.com/software-licensing/user-based-licensing/) expands beyond license keys and incorporates other user-provided credentials, such as name, email, password, or other fields, for authentication and usage. In this approach, license activation may not rely solely on a license key, but rather on user account credentials. This type of licensing is common for online services like content streaming or database access.

## **Validity Period**

When configuring a new product within LicenseSpring, you can define the default validity period for generated license keys. The validity period represents the number of days between the first activation of the license key and its expiration. License keys can be set to be valid indefinitely (perpetual) or for a specific limited period of time.

[title] License API Collection
[path] Common Scenarios/Glossary/Postman Collections/

## Base URL and Authentication Requirements

### License API Base URL

All License API requests must use the License API domain:
[**https://api.licensespring.com**](https://api.licensespring.com)

Do not use [**https://saas.licensespring.com**](https://saas.licensespring.com) for License API requests.
The saas domain is reserved for the Management API.

### Required Authentication Keys

The License API supports the following authentication methods:

- apiKey&#x20;
- sharedKey&#x20;

Both keys must be configured in the environment for Shared Key authentication workflows.

### OAuth Authentication (optional)

If using the OAuth version of the License API, the following credentials are required:

- client\_id&#x20;
- client\_secret&#x20;

The OAuth collection will obtain an access token using these values and automatically apply it to subsequent requests.

###

## **License API Environment Variables**

Used by **License API** and **License API – OAuth** collections.

| Variable                                     | Description                                                            |
| -------------------------------------------- | ---------------------------------------------------------------------- |
| default\_product\_code                       | Product code associated with the license.                              |
| default\_license\_key                        | License key used for activation/validation.                            |
| default\_hardware\_id                        | Hardware ID for binding and validation.                                |
| default\_feature\_code                       | Feature identifier for license feature operations.                     |
| default\_username / default\_password        | Used for user-based licenses.                                          |
| default\_customer\_account\_code             | Customer account reference used by some endpoints.                     |
| default\_license\_id / default\_bundle\_code | Identifiers for specific license or bundle operations.                 |
| request                                      | Required for offline flows. Must be set to activation or deactivation. |

Values can be set manually or retrieved through License API requests or the LicenseSpring UI. Please populate fields based on your use case for each endpoint.

# **How the Collections Work**

### **License api collection**

**Purpose:**
&#x20;To interact with licensing endpoints using either **API Key/Shared Key** authentication.

**Requirements:**
&#x20;Most requests require:

- default\_product\_code&#x20;
- default\_license\_key&#x20;
- default\_hardware\_id&#x20;

Headers such as **Date** and **Authorization** are generated automatically.

### License api - Oauth collection

**Purpose:**
&#x20;To interact with License API endpoints using OAuth 2.0 authentication.

**Usage:**
&#x20;Set **client\_id** an&#x64;**&#x20;client\_secret** in the environment from opur vendor platform.
&#x20;The collection obtains an access token automatically and uses it for all subsequent licensing requests.

## **Manual variable adjustment (optional)**

If you want to test with a specific license key, hardware ID, feature code, or bundle ID, you may replace the corresponding environment variable manually.

For example:

1. Open the LicenseSpring platform UI.&#x20;
2. Copy the license key or product code you want to test.&#x20;
3. Paste it into the relevant environment variable (default\_license\_key, default\_product\_code, etc.).&#x20;
4. Re-run the desired request.&#x20;

You may also temporarily place literal values directly into the request body. Every needed variable can be found and created through our vendor platform.&#x20;

## **Offline Licensing Notes**

Some License API workflows require special handling:

- Offline activation&#x20;
- Offline deactivation&#x20;
- v2 offline schema&#x20;

In these cases, the variable request must be set to:

:::BlockQuote
activation
:::

or

:::BlockQuote
deactivation
:::

Ensure the final JSON object in the body does **not** contain trailing commas when uncommenting optional parameters.

examples of available offline requests **v1** used for **activation/deactivation&#x20;**:
`{{offline_request_file}}` -> used for key-based license
`{{offline_request_file_bundle}}` -> used for key-based bundle licenses
`{{offline_request_file_user}`} -> used for user-based licenses
`{{offline_request_file_user}}` -> can also be used for user-based licenses if **default\_product\_code** points to bundle\_code, can be done inside environment by setting that variable

examples of available offline requests **v2** used for **activation/deactivation&#x20;**:
`{{offline_request_file_v2}}` -> key-based licenses - also can be used for bundle if **default\_product\_code** set to bundle\_code,can be done inside environment by setting that variable
`{{offline_request_file_v2_user}}` -> user-based licenses - also can be used for bundle if **default\_product\_code** set to bundle\_code, can be done inside environment by setting that variable

## Data manipulation

For manual data manipulation, the same principles apply as with the Management API.

If any aspect is unclear, kindly consult our official [**License API**](docId:35HkSz8vrz5Kpu1h8EHqb) documentation for each request.

Please check your company settings and under preferences tab you will see:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/0lAc7IXDPDuiNtp8uv2KV_image.png)

**Some of the license api requests depends on the selected settings in order to work, so keep that in mind.**

Remember to review any comments associated with each request. For instance, to enable the floating release functionality, you should edit the desired license, verify the floating cloud checkbox via the platform, and subsequently execute the request to ensure proper operation.

![Floating Cloud Checkbox Selected.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/LLG6t0Hu92bjHPFY-7_lT_image.png "Floating Cloud Checkbox Selected.")

## Floating Release

Example Comment: Verify Floating Cloud Status on Desired License via Platform

Here's an example of how to perform this check using two different scenarios: license-based and user-based.

### License-Based Verification

For license-based verification, use the following request body:

```json
{
  "license_key": "{{activate}}",
  "hardware_id": "{{hardware_id}}",
  "product": "{{product_code}}"
}
```

### User-Based Verification

For user-based verification, utilize the following request body:

```json
{
  "hardware_id": "{{default_hardware_id}}",
  "product": "{{default_product_code}}",
  "username": "{{default_username}}",
  "password": "{{default_password}}",
}

```

:::hint{type="info"}
**Note:&#x20;**&#x59;ou can also use the same environment as on our management API with the provided data.
:::


[title] Borrow license slot
[path] Floating Server/Floating Server V1/API Reference/registration/

{
  "id": "4Va5HuGXtwiYV6FH0A8SL",
  "data": {
    "url": "http://localhost:8080/api/v4/borrow",
    "name": "Borrow license slot",
    "method": "POST",
    "request": {
      "pathParameters": [],
      "queryParameters": [],
      "headerParameters": [],
      "bodyDataParameters": [
        {
          "kind": "optional",
          "name": "body",
          "type": "object",
          "schema": [
            {
              "kind": "optional",
              "name": "product",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "user",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "os_hostname",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "ip_local",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "user_info",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "borrowed_until",
              "type": "string",
              "example": ""
            }
          ],
          "isExpanded": true
        }
      ],
      "formDataParameters": []
    },
    "responses": [
      {
        "statusCode": "200",
        "description": "",
        "jsonExample": ""
      }
    ],
    "contentType": "application/json"
  },
  "type": "api-oas-v2",
  "children": [
    {
      "text": ""
    }
  ]
}
[title] Configuration & Provisioning
[path] Floating Server/Floating Server V2/

## **Create the Configuration File&#x20;**

:::hint{type="success"}
A **configuration file&#x20;**&#x63;an be created using the **vendor platform** instead of manually. Using the UI ensures all required fields are correctly configured and helps reduce the risk of errors. For a step-by-step guide[**Auto-Generated Config File Guide**](docId\:w51OtUIh9Tqm7rBMpqOy-)
:::

1. Create a folder named `config` next to your Floating Server binary.
2. Inside this folder, create a file name&#x64;**&#x20;default.yaml:**

:::BlockQuote
config/default.yaml
:::

Use the following template: 

```yaml
database:
 # if using sqlite
  type: sqlite
  path: ./data/db.sqlite
# if using sqlcipher
  type: sqlcipher        # <-- switch from sqlite to sqlcipher
  path: ./data/app.db
  password: "your-password" 
# if using postgres
  type: postgres
  host: localhost
  port: 5432
  user: fsuser
  password: fspassword
  name: fsdb
  sslmode: "disable"   # options: disable, require, verify-ca
  sslrootcert: "/path/to/sslcert/ca.crt" # ignore if sslmode: "disable"
  CryptoProviderKey: "" # secret used to encrypt db data in OAuth mode

server:
  port: 8080 # port on which the server runs
  Verbose: true # level of information given in logs
  DisableUserAuth: false # disable user authentication requirement, not admin!

cloud:
  UseOAuth: false
  # if authenticating with API/Shared key
  APIKey: ""
  SharedKey: ""
  # if authenticating with OAuth
  ClientId: ""
  ClientSecret: ""
  # cloud server config
  BaseURL: "" # default: "https://api.licensespring.com"
  APIPrefix: "" # default: "/api/v4/"
  ServerPublicKey: "" # default: LicenseSpring Prod's public key
  # if having Airgap licenses, fetch this key from platform
  AirgapPublicKey: ""
  # provisioning config
  UseHardwareKey: false # choose provisioning method
  HardwareKeyPIN: "" # optional, custom PIN
  PrivateKeyPath: "" # path to generated priv key. Ignore if using hardware key
  CertificatePath: "" # path to cert received from LS
```

:::hint{type="warning"}
**Comment out&#x20;**&#x6F;r **remove&#x20;**&#x74;he fields for th&#x65;**&#x20;database type&#x20;**&#x79;ou are not using.&#x20;
:::

## **Database Configuration&#x20;**

The database section defines how the application connects to the underlying database. Two database types are currently supported: **SQLite** and **PostgreSQL**.

### **SQLite**

:::hint{type="warning"}
When using SQLite, make sure the database directory specified in the YAML configuration file actually exists. For example, if you're using `./data/db.sqlite` as shown in the sample above, ensure that the `data` directory exists. The Floating Server will not create missing directories automatically. The database file can be named anything. The server will create it if it doesn't exist.
:::

If you're using SQLite, provide the file path for the database file:

:::BlockQuote
type: sqlite
path: ./data/db.sqlite
:::

### **SQLCipher Integration**

Starting from [**v2.1.0,**](https://docs.licensespring.com/Floating-server-v2/overview-and-installation#RBuN1) we offer **full encryption of the SQLite database**.
To enable it:

- In your **config file**, set the database type to **sqlchiper** instead of sqlite.
- Before running the server, **install SQLCipher** on your system (Linux or Windows) and ensure your app links to it.

### **Installing SQLCipher**

**Linux**

```bash
sudo apt update
sudo apt install sqlcipher libsqlcipher-dev
```

**Windows**

If you’re on Win 10 or above, install WSL on Windows and run&#x20;

```bash
sudo apt-get install sqlcipher
```

### **PostgreSQL**

Update the `default.yaml` file with the following:&#x20;

**Fields:**

- `host`: The `PostgreSQL` server address (usually `localhost` for local development)
- `port`: Port number (default is `5432`)
- `user`: The PostgreSQL username
- `password`: The password for the specified user
- `name`: The name of the database to connect to

:::BlockQuote
type: postgres
host: the posgres host
port: the postgres port
user: the user in db
password: password
name: give the db a name
:::

**Setting Up PostgreSQL (Local)**

- Install PostgreSQL (if not installed)
- Create the database and user: `psql postgres`inside the psql prompt:

:::CodeblockTabs
sql

```pgsql
CREATE DATABASE fsdb;
CREATE USER fsuser WITH PASSWORD 'fspassword';
GRANT ALL PRIVILEGES ON DATABASE fsdb TO fsuser;
```
:::

- Verify the connection:


:::CodeblockTabs
```bash
psql -h localhost -U fsuser -d fsdb
```

```powershell
psql -h localhost -U fsuser -d fsdb
```
:::

- You will be prompted to enter the password you set for the database user  (e.g.`,fspassword `or the password you chose).&#x20;
- This process in MacOS is shown in the following picture.&#x20;

![](https://archbee-image-uploads.s3.amazonaws.com/6CLcmIv1QNNDgKDDEXj7l-wZn45Xy7Fpmp843-vU5I0-20250808-014609.png)

**CryptoProviderKey**

`CryptoProviderKey` is a secret key you may use to encrypt data before storing it in the database.

:::hint{type="warning"}
**OAuth:** You must set `CryptoProviderKey `to encrypt data in the database.

**API/Shared Keys:** Not required; the database uses `SharedKey` for encryption automatically.
:::

## Server Configuration

- **Port:** Network port the server listens on.
- **Verbose:** Set **true** for development logs, **false** for production.
- **DisableUserAuth:** Only set true for testing; this disables user authentication for license management features.

## Cloud Configuration&#x20;

- **API/Shared Keys:** Fill APIKey and SharedKey.
- **OAuth:** Set UseOAuth: true and provide ClientId, ClientSecret, and CryptoProviderKey.
- If your **BaseURL** or **APIPrefix** differs from the defaults, specify them in the cloud section. You must also provide the server’s public key in the following format:&#x20;

```yaml
ServerPublicKey: |
  -----BEGIN PUBLIC KEY-----
  (your public key here)
  -----END PUBLIC KEY-----

```

:::hint{type="success"}
**Floating Server v2.2.0+:&#x20;**&#x54;he private key PEM supports either BEGIN RSA PRIVATE KEY or BEGIN PRIVATE KEY .
:::

## Provisioning the Floating Server&#x20;

Provisioning ensures that only authorized instances of the server are allowed to run.

Starting with **Floating Server v2.2.0**, provisioning can be completed using **either**:

- **Hardware Key authentication(**&#x59;ubiKe&#x79;**)**, or&#x20;
- The previously supported **certificate-based method (CSR)**&#x20;

Both provisioning options are available and managed through the **LicenseSpring Platform**. This section provides a high-level overview; detailed steps for each method are outlined below.&#x20;

### Floating Server Provisioning with Certificates (CSR)

**Step 1: Generate a Key Pair**

:::BlockQuote
openssl genrsa -out private.key 2048
:::

**Step 2: Provision via LS Platform**

1. Open the LicenseSpring Platform.
2. Navigate to **Enterprise Company → Licenses → Floating Servers**.
3. Click **Provision the Floating Server**.

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/kwNJGM4CBkquzBJotnWHb_image.png" signedSrc size="100" width="2360" height="849" position="center" caption="Provisioning the Floating Server" alt darkWidth="2360" darkHeight="849" indent="2"}

4. Choose **Certificate** as the authentication type.
5. Enter a name and optional expiration date.
6. Generate a **CSR (Certificate Signing Request)** locally.
7. Copy the contents of request.csr into the LS Platform form on the below and click **Confirm**.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ajOkbFAEGrP77Z8AkHP4a_image.png "Floating Server Provisionning - Generate CSR")

**Step 3:** **Download and Save Certificates**

- Save the issued certificate (e.g., certificate.crt).
- Generate the chain certificate from platform as shown below (e.g., chain.pem)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/aT5YSfZs1LZi0bmUZaP-C_image.png)

- Keep your private key accessible.

**Step 4:&#x20;**&#x55;pdate **default.yaml**

```yaml
cloud:
  UseHardwareKey: false # choose provisioning method
  PrivateKeyPath: "" # ignore if using hardware key
  CertificatePath: "" # ignore if using hardware key
```

## **Floating Server Provisioning Using a Hardware Key**

As an alternative to certificate-based provisioning, the Floating Server can be provisioned using a **hardware key (dongle)**. This method authorizes the server based on the presence of a physical security device connected to the machine. When a hardware key is enabled, the Floating Server workflow remains largely the same as in the previously described examples, with the added requirement of a connected hardware key.

Use this option when physical enforcement or offline licensing is required.

### Optional: Set a Custom Hardware Key PIN

Before starting the provisioning process with a hardware key, you may choose to **update the default hardware key PIN**. If you set a custom PIN, ensure that the new value is included in the Floating Server configuration file, as shown below.

### Configuration for Hardware Key Provisioning

When provisioning with a hardware key, update the configuration file(**default.yaml**) accordingly:

```yaml
UseHardwareKey: true # choose provisioning method
HardwareKeyPIN: "" # optional, custom PIN
CertificatePath: "" # path to cert received from LS
```

To use a YubiKey with the Floating Server, set the `UseHardwareKey` configuration value to `true`. When this option is enabled, the server detects the hardware key and establishes the connection during startup.

:::hint{type="info"}
The Floating Server only checks for the hardware key during startup. If the key is unplugged while the server is running, the connection cannot be re-established automatically.
:::

### Requirements

- A supported hardware key (YubiKey)
- Hardware key drivers installed on the server&#x20;
- Hardware key physically connected to the Floating Server machine&#x20;
- Required permissions are needed to perform this action


**Step 1: Provision the Floating Server**

1. Open the **LicenseSpring Platform**&#x20;
2. Navigate t&#x6F;**&#x20;→ Licenses → Floating Servers**&#x20;
3. Click **Provision the Floating Server**&#x20;
4. Enter a server name
5. Select **Hardware Key** as the authentication type&#x20;
6. Follow the steps on the below screenshot
7. Click **Confirm**&#x20;

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/bhfxIgXoznjs0lR2wdatk_provisioning-floating-server-yubikey.png)

The Floating Server is now registered to use hardware key authentication.

:::hint{type="info"}
To download the YubiKey provisioning application, refer to the **Hardware Key Licensing&#x20;**[**documentation.**](https://docs.licensespring.com/license-entitlements/activation-types/hardware-keys#kMYEO)
:::

### &#xA;**Create a License for Hardware Key–Based Floating Server Use**

After provisioning the Floating Server with a hardware key, you must create a license that is **explicitly enabled for hardware key usage**.

When creating or editing the license in the LicenseSpring Platform:

1. Navigate to **Licenses**&#x20;
2. Create a new license&#x20;
3. Enable the **Required Hardware Key** option (checkbox)&#x20;
4. Save the license&#x20;

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ixrUwkPbFj_BXvOliqTTY_require-hardware-key.png)

Only licenses with the **Hardware Key** option enabled can be used with a Floating Server that is provisioned using a hardware key.

:::hint{type="info"}
Licenses without this option enabled will not be accepted by a hardware key–provisioned Floating Server.
:::

### **Hardware Key and Server Lifecycle**

In Floating Server v2.2.0, the server’s lifecycle is tightly coupled to the hardware key connection:

- When the server starts, it establishes a connection to the hardware key.&#x20;
- When the server shuts down, the hardware key connection is closed.&#x20;
- If the hardware key is disconnected while the server is running, the server will shut down gracefully.&#x20;

:::hint{type="warning"}
**Current Limitations**

As of v2.2.0, **offline bundles** and **air-gapped licenses** are not supported when using a hardware key. Support for these scenarios will be added in future versions.
:::


[title] Generate offline license request
[path] Floating Server/Floating Server V1/API Reference/license/

{
  "id": "95odUSQdHr3grg5Erasdr",
  "data": {
    "url": "http://localhost:8080/api/v4/license/generate",
    "name": "Generate offline license request",
    "method": "POST",
    "request": {
      "pathParameters": [],
      "queryParameters": [],
      "headerParameters": [],
      "bodyDataParameters": [
        {
          "kind": "optional",
          "name": "body",
          "type": "object",
          "schema": [
            {
              "kind": "optional",
              "name": "product",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "license_key",
              "type": "string",
              "example": ""
            }
          ],
          "isExpanded": true,
          "description": "Generate "
        }
      ],
      "formDataParameters": []
    },
    "responses": [
      {
        "isExpanded": true,
        "statusCode": "200",
        "description": "OK",
        "jsonExample": ""
      }
    ],
    "contentType": "application/json"
  },
  "type": "api-oas-v2",
  "children": [
    {
      "text": ""
    }
  ]
}
[title] Unregister user
[path] Floating Server/Floating Server V1/API Reference/registration/

{
  "id": "_JG-jGzcAAY1aDjF80ulx",
  "data": {
    "url": "http://localhost:8080/api/v4/unregister",
    "name": "Unregister user",
    "method": "POST",
    "request": {
      "pathParameters": [],
      "queryParameters": [],
      "headerParameters": [],
      "bodyDataParameters": [
        {
          "kind": "optional",
          "name": "body",
          "type": "object",
          "schema": [
            {
              "kind": "optional",
              "name": "product",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "user",
              "type": "string",
              "example": ""
            }
          ],
          "isExpanded": true
        }
      ],
      "formDataParameters": []
    },
    "responses": [
      {
        "statusCode": "200",
        "description": "",
        "jsonExample": ""
      }
    ],
    "contentType": "application/json"
  },
  "type": "api-oas-v2",
  "children": [
    {
      "text": ""
    }
  ]
}
[title] Generate airgap signature
[path] Floating Server/Floating Server V1/API Reference/license/

{
  "id": "IbvloJ9tzo6zWqHHzORVB",
  "data": {
    "url": "http://localhost:8080/api/v4/airgap/generate",
    "name": "Generate airgap signature",
    "method": "POST",
    "request": {
      "pathParameters": [],
      "queryParameters": [],
      "headerParameters": [],
      "bodyDataParameters": [
        {
          "kind": "optional",
          "name": "body",
          "type": "object",
          "schema": [
            {
              "kind": "optional",
              "name": "license_key",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "signing_key",
              "type": "string",
              "example": ""
            }
          ],
          "isExpanded": true
        }
      ],
      "formDataParameters": []
    },
    "responses": [
      {
        "isExpanded": true,
        "statusCode": "200",
        "description": "OK",
        "jsonExample": ""
      }
    ],
    "contentType": "application/json"
  },
  "type": "api-oas-v2",
  "children": [
    {
      "text": ""
    }
  ]
}
[title] Register user
[path] Floating Server/Floating Server V1/API Reference/registration/

{
  "id": "1o0xNo5bvZW-7ZM5ClOPa",
  "data": {
    "url": "http://localhost:8080/api/v4/register",
    "name": "Register user",
    "method": "POST",
    "request": {
      "pathParameters": [],
      "queryParameters": [],
      "headerParameters": [],
      "bodyDataParameters": [
        {
          "kind": "optional",
          "name": "body",
          "type": "object",
          "schema": [
            {
              "kind": "optional",
              "name": "product",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "user",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "os_hostname",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "ip_local",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "user_info",
              "type": "string",
              "example": ""
            }
          ],
          "isExpanded": true
        }
      ],
      "formDataParameters": []
    },
    "responses": [
      {
        "isExpanded": true,
        "statusCode": "200",
        "description": "OK",
        "jsonExample": ""
      }
    ],
    "contentType": "application/json"
  },
  "type": "api-oas-v2",
  "children": [
    {
      "text": ""
    }
  ]
}
[title] Add airgap license
[path] Floating Server/Floating Server V1/API Reference/license/

{
  "id": "p2EWDt6dL3GkZg3cdC9EQ",
  "data": {
    "url": "http://localhost:8080/api/v4/airgap/license",
    "name": "Add airgap license",
    "method": "POST",
    "request": {
      "pathParameters": [],
      "queryParameters": [],
      "headerParameters": [],
      "bodyDataParameters": [
        {
          "kind": "optional",
          "name": "body",
          "type": "object",
          "schema": [
            {
              "kind": "optional",
              "name": "license_policy",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "license_key",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "policy_id",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "confirmation_code",
              "type": "string",
              "example": ""
            }
          ],
          "isExpanded": true
        }
      ],
      "formDataParameters": []
    },
    "responses": [
      {
        "isExpanded": true,
        "statusCode": "200",
        "description": "OK",
        "jsonExample": ""
      }
    ],
    "contentType": "application/json"
  },
  "type": "api-oas-v2",
  "children": [
    {
      "text": ""
    }
  ]
}
[title] Auto-Generated Config File Guide
[path] Floating Server/Floating Server V2/Untitled/

:::hint{type="danger"}
Before creating an auto-generated configuration file, the [**provisioning process&#x20;**](https://docs.licensespring.com/configuration-and-provisioning#BLTVg)must be completed. Once provisioning is finished, the floating server will appear in the **Floating Servers** list and can then be used to generate the configuration file.
:::

To create a configuration file for a floating server, the setup must be completed through the vendor platform. This process ensures that all required parameters are properly captured and reduces the risk of misconfiguration. Follow the steps below to generate the configuration file and download both th&#x65;**&#x20;.YAML file** and the **Certificate Chain.**

## 1. Access the Vendor Platform&#x20;

Navigate to the vendor platform and go to the **Licenses** section.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/rIw_gSXctyjR-eqOabKOz_image.png)

## 2. Select Floating Servers&#x20;

Click on **Floating Servers**. After completing the provisioning process, all floating servers will be listed below. Click on the desired floating server from the list.

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/YYkw-495pD3MrcW0rWUbf_image.png "Select Floating Server from List")

## 3. Create/Edit Configuration File&#x20;

On the **Floating Server details** page, click **Create/Edit Config File**. A popup window will appear where you can select the **database type**. Complete all required fields based on your configuration.

See the screenshots below for examples.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/f350KZrL5h2PXoLGlgsqP_image.png)

In the popup window, the **Database Type** dropdown provides two options:

- **SQLite**&#x20;
- **PostgreSQL**&#x20;

See the screenshots below for examples of each option:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/3tUPmxb-PKTiP8kpoSBoE_image.png)

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/pgFZvlhnxaV206_EHycM0_image.png "SQLite option selected")

:::hint{type="info"}
The required fields in the configuration popup may differ depending on whether **SQLite** or **PostgreSQL** is selected. For details on the specific values needed, please refer to the [**Configuration and Provisioning**](https://docs.licensespring.com/configuration-and-provisioning#BLTVg) page.&#x20;
:::

## 4. Download Configuration Files&#x20;

### 1.Download **YAML**

&#x20; Downloads the configuration file in **YAML format.**

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/bixVEM12YR8uJOOX79gN5_image.png "Download YAML Button")

### **2.Download Certificate Chain**&#x20;

Downloads the full certificate chain, including leaf, root, and intermediate certificates.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ia2zRpGDhN0xrNj5PeIlW_image.png)




[title] Unregister all users
[path] Floating Server/Floating Server V1/API Reference/registration/

{
  "id": "m3hidxgQzRKJqTdmJAdtB",
  "data": {
    "url": "http://localhost:8080/api/v4/unregister/all",
    "name": "Unregister all users",
    "method": "GET",
    "request": {
      "pathParameters": [],
      "queryParameters": [],
      "headerParameters": [],
      "bodyDataParameters": [],
      "formDataParameters": []
    },
    "responses": [
      {
        "statusCode": "200",
        "description": "",
        "jsonExample": ""
      }
    ],
    "contentType": "application/json"
  },
  "type": "api-oas-v2",
  "children": [
    {
      "text": ""
    }
  ]
}
[title] User portal SSO
[path] Common Scenarios/Single Sign On (SSO)/

LicenseSpring supports two main end-user authentication scenarios:

1\. **User Portal SSO**

The User Portal is a hosted interface provided by LicenseSpring where end users can:

- View and manage their licenses
- Access self-service tools (e.g., license transfers, device resets)

With SSO enabled, users can sign in to this portal using their organization’s identity provider, without needing separate LicenseSpring credentials.

2\. **License Activation via SSO**

When SSO is enabled for license activation, end users authenticate with your IdP before activating a license. This ensures licenses are securely tied to verified user identities, and that only authorized users can activate or use your software.

This method is supported via the LicenseSpring SDKs and API, and is particularly useful for:

- Subscription-based licensing models
- User based licensing
- Restricting license access to organizational members

The next section explains how to access and configure SSO settings for these scenarios within the LicenseSpring Vendor Platform.

:::hint{type="info"}
Please note that license users SSO (Single Sign On) is only available on Enterprise plan. It allows using Single Sign On method for license activation.
:::

## Setup Single Sign On

LicenseSpring supports end-user Single Sign-On (SSO) through **Customer Accounts**,  allowing software vendors to authenticate users within the context of a specific customer organization.

Each Customer Account can be linked to its own identity provider (IdP), enabling tailored SSO configurations for different enterprise clients. By associating SSO with Customer Accounts, LicenseSpring ensures that license access and portal authentication are securely scoped to the correct organization.

Follow the steps below to access the SSO configuration view:

1. **Log in to the Vendor Platform**
   - Go to [**https://saas.licensespring.com**](https://saas.licensespring.com) and sign in with your admin credentials.
2. **Navigate to Customer Accounts**
   - On your sidebar menu select **Customer accounts**
   - Here, you can either select an existing customer account from the list or create a new one using the `Add new account` button.&#x20;
3. **Select the “Single Sign On” Tab**
4. After you have created or selected existing customer account, visit its Single Sing On settings tab.
5. In this section, you have the option to activate SSO and gather any necessary data to ensure its seamless setup and operation.

![Single Sign On Tab](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/wAXQjZhGXipVGhBXooqey_image.png "Single Sign On Tab")

**4. Click “Add  Provider”**

![Add Provider Button](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/IzikW9gdmqPGpK_HTtfTn_image.png "Add Provider Button")

1. To begin the integration process, click on the **“Add Provider”** button.
2. You will be prompted to enter details based on your IdP’s protocol (SAML or OIDC).

![](https://archbee-image-uploads.s3.amazonaws.com/U9x6bSuQrpDmdgq5PGwu3-q451GZupje6qEMUrZ-Qre-20250422-091949.png "Add SSO Provider form")

Depending on your selected Identity Provider, you will have to submit following informations:

- `Name` and `.xml provider metadata file` for SAML providers.
- `Name`, `Client ID` and `Client secret` for Google identity provider.
- `Service ID`, `Key ID`, `Team ID` and` .p8 key file` for Apple identity provider.

:::hint{type="info"}
You can use only one provider at time, if you wish to switch to another, first delete old one then follow our setup guide to add specific new provider.
:::

### Account Linking and Verification



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/AJNVpyKd-XKjnfWH0YIny_image.png)

LicenseSpring automatically links accounts **if the email in our system matches the email from the IdP**.
If no match is found, the user is presented with a **login prompt** to link their existing LicenseSpring account.

The settings toggle `Require email verification on first SSO login` can be enabled to require email verification before linking an account.

If the Account Linking and Verification toggle is **ON**, then when you create a user, they must verify their email before they can log in.
If the toggle is **OFF**, email verification is not required for the user to log in.
For platform users, email verification is always required due to account sensitivity.

Instructions on how to register your application to acquire required informations are described below.

### Redirect URI

When configuring SSO for license activation, the `redirect_uri` should be a local endpoint within your application that is capable of receiving and processing the authentication response from your identity provider. This URI must be registered with the IdP and securely handle the token or authorization code required to complete the sign-in and license activation flow

`redirect_uri `is only relevant for applications that use the SDK and allow licensed users to use SSO instead of email/password for authentication.
Otherwise, everything else redirects back to the user portal.

### **Extracting the Company Code**

You will need Company code to succesfully register your application in your identity provider dashboard. To find your company code, follow the next steps:

- Inside LicenseSpring vendor platform navigate to **Settings--> Preferences**&#x20;
- Pay attention to the **Company code** field. In this case Company code is **DSE2**



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/3syMEq4bbwIlNOMnOIREn_image.png "Company code")

### **Extracting the Customer Account Code**

You will also need Customer account code to succesfully register your application in your identity provider dashboard. To find the correct customer account code, follow the next steps:

- Inside LicenseSpring vendor platform navigate to the Customer Account page for which you want to setup SSO
- Pay attention to the **code** field. In this case Customer Account code is **test678**



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/FV-Q8vUa_Adz6a65lmAg8_image.png "Customer Account page")

## Integrating Social Identity Providers

Before setting up a social IdP, it's necessary to register your application with the respective IdP to acquire a client ID and client secret.

### Google

1. [**Create a developer account**](http://developers.google.com/identity) with Google if you haven't already.
2. Access the [**OAuth consent screen page**](https://console.cloud.google.com/apis/credentials/consent).
3. **Create a New Project**:
   - Click on the project dropdown at the top left.
   - Select "New Project".
   - Name your project (e.g., Google) and click "Create".

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/mZh3i1Fv9kJtZ8wtlxTPD_image.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/mZh3i1Fv9kJtZ8wtlxTPD_image.png" size="100" caption isUploading="false" width="1360" height="1056" indent="3"}

4. **Set Up OAuth Consent Screen**:
   - Navigate to the "OAuth consent screen" tab.
   - Select "External" and click "Create".
   - Fill in the required fields such as "Application name" and "User support email".
   - Configure Scopes: Include Scopes like:&#x20;
   - `.../auth/userinfo.email, `
   - `.../auth/userinfo.profile, `
   - `openid`
   - Continue to Test users settings and save.
   - add test users inside the application:

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/pPf-5hPjk-Bza3NeM-Mtt_image.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/pPf-5hPjk-Bza3NeM-Mtt_image.png" size="100" caption isUploading="false" width="1064" height="446" indent="3"}

5. **Create OAuth 2.0 Credentials**:
   - Go to the "Credentials" tab.
   - Click "Create Credentials" and select "OAuth 2.0 Client ID".
   - Select "Web application".
   - Provide a name for the OAuth client (e.g., MyClient)
   - Add **\<domain> for our platform&#x20;**&#x74;&#x6F;**&#x20;Authorized JavaScript origins**
   - e.g.[ ]()[**auth.licensespring.com**](http://auth.licensespring.com)
   - and you can also add here second one but not required to work:&#x20;
   - ****[**users.licensespring.com**](http://users.licensespring.com)
   - In the "**Authorized redirect URIs**" section, add the redirect URL:&#x20;
   - **https\://\<domain>/realms/\<realm>/broker/\{COMPANY\_CODE}-\{CUSTOMER\_ACCOUNT\_CODE}/endpoint**
   - e.g. [**https://auth.licensespring.com/realms/user-portal/broker/tbc-ssoacc/endpoint**](https://auth.dev.licensespring.com/realms/user-portal/broker/tbc-ssoacc/endpoint)
   - Click "Create".
6. **Save Your Credentials**:
   - Once created, you will be provided with a **Client ID** and **Client Secret.**
   - Copy and save these credentials. You will need them to configure your application to use Google SSO inside the platform.
   - Go back to `Add SSO Provider` form in the LicenseSpring vendor platform and finish the setup.

### Apple

1. **Go to the Apple Developer Console**: Visit [**Apple Developer Console**](https://developer.apple.com/account).
2. **Create an Apple Developer Account**:
   - If you don't have an Apple Developer account, you will need to create one and enroll in the Apple Developer Program.
3. **Create a New App ID**:
   - Navigate to "[**Certificates, Identifiers & Profiles**](https://developer.apple.com/account/resources/identifiers/list)".
   - Under Identifiers, click the "+" button to create a new App ID.
   - Choose "App IDs" and click "Continue".
   - Enter a description and a bundle ID (e.g., keycloak)
   - Under "Capabilities", enable "Sign in with Apple".
   - Click "Continue" and then "Register".
   - Enable as a  on configuration of **Sign in with Apple.**

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/LYzOh59h3_Mmp50vDr2n8_image.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/LYzOh59h3_Mmp50vDr2n8_image.png" size="100" caption isUploading="false" width="1312" height="986" indent="3"}

4. **Create a Service ID**:
   - Still under "Identifiers", click the "+" button to create a new Service ID.
   - Select "Service IDs" and click "Continue".
   - Enter a description and an identifier (e.g., **keycloak-service**)
   - Click "Continue" and then "Register".
   - After creating the Service ID, click on it to edit it.
   - Enable "Sign in with Apple" and configure the **Return URLs** to:[ ]()[**https://auth.licensespring.com/realms/user-portal/broker/\{COMPANY\_CODE}-\{CUSTOMER\_ACCOUNT\_CODE}/endpoint**](https://auth.licensespring.com/realms/user-portal/broker/\{COMPANY_CODE}-\{CUSTOMER_ACCOUNT_CODE}/endpoint)
   - e.g. [**https://auth.licensespring.com/realms/user-portal/broker/tbc-tas/endpoint**](https://auth.licensespring.com/realms/user-portal/broker/tbc-tas/endpoint)
   - and add **Domains and Subdomains for our platform( without http\:// or https\://)** to:
   - [**auth.licensespring.com**](http://auth.licensespring.com)

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/LfCcgdGRYyDD9__HisZVJ_image.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/LfCcgdGRYyDD9__HisZVJ_image.png" size="100" caption isUploading="false" width="1314" height="1014" indent="3"}

:::Paragraph{listStyleType="disc" listStart="10" indent="2"}
Add the primary App ID created earlier as the Primary App ID.
:::

:::Paragraph{listStyleType="disc" listStart="11" indent="2"}
Click "Save".
:::

5. **Create a Key for Apple Sign-In**:
   - Navigate to "Keys" and click the "+" button to create a new key.
   - Enable "Sign in with Apple" and click "Configure".
   - Select the Primary App ID and click "Save".
   - Click "Continue" and then "Register".
   - Download the key file it will have a .p8 extension) and save it securely. You will not be able to download it again.
6. **Get Your Team ID and Key ID**
7. Note down your **Team ID** from your Apple Developer account.
8. Note down the **Key ID** from the key details.
9. Note down service identifier as mentioned before in step 4. : **keycloak-service**
10. Have your **key file** ready to upload it on platform.&#x20;
11. Go back to `Add SSO Provider` form in the LicenseSpring vendor platform and finish the setup.

:::hint{type="warning"}
When you create new APP ID, it may take up to few hours to apply changes.
:::

## Incorporating SAML Identity Providers

### Azure Active Directory

1. Access [**Azure Portal**](https://portal.azure.com/) and choose **Enterprise Applications**.
2. Add an enterprise application.
3. Create your own application, input name, and select **non-gallery** option.
4. Opt for single sign-on > SAML.
5. **Set up single sign on**
6. Edit Basic SAML Configuration:
   - Identifier (Entity ID) **:&#x20;**[**https://auth.licensespring.com/realms/user-portal**](https://auth.licensespring.com/realms/user-portal)
   - Reply URL (Assertion Consumer Service URL)**:&#x20;**[**https://auth.licensespring.com/realms/user-portal/broker/\{COMPANY\_CODE}-\{CUSTOMER\_ACCOUNT\_CODE}/endpoint**](https://auth.licensespring.com/realms/user-portal/broker/\{COMPANY_CODE}-\{CUSTOMER_ACCOUNT_CODE}/endpoint)
   - e.g. [**https://auth.licensespring.com/realms/user-portal/broker/tbc-tas/endpoint**](https://auth.licensespring.com/realms/user-portal/broker/tbc-tas/endpoint)
7. Save and close the settings.
8. Under **Attributes & Claims&#x20;**&#x70;lease set if not selected **Unique User Identifier(Name ID)&#x20;**&#x74;o **user.mail**:



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/1G-bCPuITsBk70oHU4DZO_image.png)

1. We are using th&#x65;**&#x20;email&#x20;**&#x61;s the **NameID**. If the **UserPrincipalName** (UPN) is not the user’s&#x20;
   - primary email in the platform, it should be updated accordingly. ***This is important as some users may have multiple email aliases, which could result in pulling the incorrect email.***
2. Download Federation Metadata XML.
3. Provide us with your provider's name and the downloaded metadata in **.xml&#x20;**&#x66;ormat.
4. Go back to `Add SSO Provider` form in the LicenseSpring vendor platform and finish the setup.
5.

:::hint{type="danger"}
**Error:&#x20;**&#x41; common Azure DB provider SSO error is shown in the screenshot below:
:::



![](https://images.archbee.com/IJdHyjBlO9LOXOrDnWJTx/lsPoyx3AW21xEQ4g-ePvK_image.png?format=webp)

To resolve this error, follow these steps:

1. In the [**Azure Active Directory Admin Center**](http://aad.portal.azure.com/#blade/Microsoft_AAD_IAM/StartboardApplicationsMenuBlade/AllApps/menuId/AllApps)**,** select your app and then search for and select the application to which you want to assign the user account.
2. In the left pane select Users and Groups and then select **Add User/Group**.

![](https://t4573966.p.clickup-attachments.com/t4573966/275a3046-6794-43bb-95d0-904013b7132e/image.png)

![](https://t4573966.p.clickup-attachments.com/t4573966/cf852e1b-72ac-4922-9a80-142e45ee431e/image.png)

3\.  On the Add Assignment pane, select None Selected under Users and Groups&#x20;

4\.  Search for and select the user that you want to assign to the application, select Select&#x20;

5\.  On the Add Assignment, select Assign at the bottom of the pane&#x20;

6\.  When all steps are completed, user can normally sign in to account using SSO.

![](https://t4573966.p.clickup-attachments.com/t4573966/82b50e77-7559-4df7-923f-e7c6d6e92569/image.png)



:::hint{type="warning"}
For SAML we use the **Name ID** format **emailaddress**.
:::

Upload the downloaded .xml file by choosing SAML for AuthO and confirm to add it.

Go back to `Add SSO Provider` form in the LicenseSpring vendor platform and finish the setup.

### Auth0

1. Access the [**AuthO website dashboard**](https://manage.auth0.com/dashboard/).
2. Click on Applications, then select Create Application.
3. In the Create Application dialog box, provide a name for your application (e.g., My App).
4. Choose **Single Page Web Applications** as the application type.
5. Click the Create button.


**Create Test user**

1. Navigate to the left navigation bar and select User Management.
2. Click on Users.
3. Choose + Create Your First User. Alternatively, if this is not your initial user, select **+ Create User.**
4. Within the Create user dialog box, input the user's email and password.
5. Click the Save button.


**Configure SAML Settings**

1. Access the left navigation bar and click on Applications.
2. Select the name of the application you previously created.
3. Go to the **Addons tab**.
4. Activate the SAML2 Web App option.
5. Within the Addon: SAML2 Web App dialog box, navigate to the Settings tab.
6. For the Application Callback URL, input:
   - **https\://\<domain>/realms/\<realm>/broker/\{COMPANY\_CODE}-\{CUSTOMER\_ACCOUNT\_CODE}/endpoint**
     - Please substitute **company code and customer account code** with the appropriate values from platform for your company\_code and customer\_account\_code, Single Sign-On (SSO) settings.
7. Under **Settings**, input the following and leave it empty: **\{}**
8. For minimal **Settings&#x20;**&#x74;o configure **email** as the **NameID**, you can use the following configuration:
   - `{`
     `  "mappings": {`
     `    "user_id": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",`
     `    "email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"`
     `  },`
     `  "nameIdentifierFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",`
     `  "nameIdentifierProbes": [`
     `    "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"`
     `  ]`
     `}`
   - \[Optional] Choose Debug, then log in as the test user you created to confirm that the configuration works.
9. Choose Enable, and then choose Save.
10. In the **Addon**: SAML2 Web App dialog box, on the Usage tab, find Identity Provider Metadata. Then do either of the following:
11. Choose download to download the **.xml&#x20;**&#x6D;etadata file.
12. Go back to `Add SSO Provider` form in the LicenseSpring vendor platform and finish the setup.

### Okta

1. Open the [**Okta Developer Console**](https://developer.okta.com/login/).
2. In the navigation menu, expand Applications, and then choose Applications.
3. Choose Create App Integration.
4. In the Create a new app integration menu, choose SAML 2.0 as the Sign-in method.
5. Choose Next.
6. On the Create SAML Integration page, under General Settings, enter a name for your app.
7. Choose Next.

**Configure SAML Integration**

1. Under GENERAL, for **Single sign on URL**:
   - [**https://auth.licensespring.com/realms/user-portal/broker/\{COMPANY\_CODE}-\{CUSTOMER\_ACCOUNT\_CODE}/endpoint**](https://auth.licensespring.com/realms/user-portal/broker/\{COMPANY_CODE}-\{CUSTOMER_ACCOUNT_CODE}/endpoint)
   - e.g. [**https://auth.licensespring.com/realms/user-portal/broker/tbc-tas/endpoint**](https://auth.licensespring.com/realms/user-portal/broker/tbc-tas/endpoint)
2. For **Audience URI (SP Entity ID)**, enter:
   - [**https://auth.licensespring.com/realms/user-portal/broker/\{COMPANY\_CODE}-\{CUSTOMER\_ACCOUNT\_CODE}/endpoint**](https://auth.licensespring.com/realms/user-portal/broker/\{COMPANY_CODE}-\{CUSTOMER_ACCOUNT_CODE}/endpoint)
   - e.g.[**&#x20;https://auth.licensespring.com/realms/user-portal/broker/tbc-tas/endpoint**]()
3. For **SAML Settings&#x20;**&#x63;hoose if not selected **NameID Format EmailAddress -&#x20;**&#x69;t's located on **General tab** under the application
4. For all other settings on the page, leave them as their default values or set them according to your preferences.
5. Choose Next.
6. Choose a feedback response for Okta Support.
7. Choose Finish.

![](https://t4573966.p.clickup-attachments.com/t4573966/cabd4b93-219f-43e2-b19c-6b83297cced6/image.png)

**Assign a User**

1. On the Assignments tab for your **Okta app**, for Assign, choose Assign to People.
2. Choose Assign next to the user that you want to assign. Note: If this is a new account, the only option available is to choose yourself (the admin) as the user.
3. (Optional) For User Name, enter a user name, or leave it as the user's email address, if you want.
4. Choose Save and Go Back. Your user is assigned.
5. Choose Done.

**Get the IdP Metadata**

1. On the **Sign On tab** for your **Okta app**, find the Identity Provider metadata hyperlink.&#x20;
2. Right-click the hyperlink, and then copy the URL.&#x20;
   - If not found then click View SAML setup instructions and save the value from Provide the following IDP metadata to your SP provider into an **.xml** file.

:::hint{type="warning"}
For SAML we use the **Name ID** format **emailaddress**.
:::

Upload the downloaded .xml file by choosing SAML for AuthO and confirm to add it.

Go back to `Add SSO Provider` form in the LicenseSpring vendor platform and finish the setup.

## OpenID Connect (OIDC) Integration

LicenseSpring Platform supports Single Sign-On (SSO) via **OpenID Connect (OIDC)**.
&#x20;Customers may integrate any identity provider that supports the standard Authorization Code Flow, including:

- **Azure Active Directory (Entra ID)**&#x20;
- **Okta**&#x20;
- **Auth0**&#x20;
- **Google Identity**&#x20;

This feature allows organizations to authenticate their users using their own identity system, while LicenseSpring handles user provisioning and access control.

### OIDC Redirect URI

Every OIDC provider must be configured to redirect authentication responses to the following URL:

[****](https://auth.licensespring.com/realms/platform/broker/\{company_code}-\{customer_account_code}/endpoint)

Replac&#x65;**&#x20;\{company\_code}** with the company code assigned to your organization in LicenseSpring.
This redirect URI **must match exactly** in your identity provider configuration.

## Google Identity (OIDC)

### Steps for Google

1. Go to [**https://console.cloud.google.com**](https://console.cloud.google.com)
2. APIs & Services → Credentials&#x20;
3. Create Credentials → OAuth client ID&#x20;
4. Application type: **Web Application**&#x20;

- Authorized JavaScript origins:

:::BlockQuote{listStyleType="disc" listStart="2" indent="1"}
[**https://auth.licensespring.com**](https://auth.licensespring.com/)
:::

- Add Authorized redirect URI:&#x20;

:::BlockQuote{listStyleType="disc" listStart="4" indent="1"}
[**https://auth.licensespring.com/realms/user-portal/broker/\{company\_code}-\{customer\_account\_code}/endpoint**](https://auth.licensespring.com/realms/user-portal/broker/\{company_code}-\{customer_account_code}/endpoint)
:::

6. Create&#x20;
7. Copy:&#x20;

- Client ID&#x20;
- Client Secret&#x20;

8. Ensure OAuth Consent Screen is configured and published

### Metadata URL


[**https://accounts.google.com/.well-known/openid-configuration**](https://accounts.google.com/.well-known/openid-configuration)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/S1nLYtoDGZaJxd2nzhIR5_image.png)

## Microsoft Azure AD (Entra ID)

### Steps in Azure

1. Sign in to Azure Portal: [**https://portal.azure.com**](https://portal.azure.com)
2. Go to **Microsoft Entra ID → App registrations → New registration**
3. **Important note:** we create **App registrations**, not Enterprise Application&#x20;
4. Enter a name (e.g., LicenseSpring OIDC)&#x20;
5. Supported account types: **Accounts in this organizational directory only**&#x20;
6. Add Redirect URI (Web):&#x20;
   [**https://auth.licensespring.com/realms/user-portal/broker/\{company\_code}-\{customer\_account\_code}/endpoint**](https://auth.licensespring.com/realms/user-portal/broker/\{company_code}-\{customer_account_code}/endpoint)
7. Click **Register**&#x20;
8. Copy **Application (client) ID**&#x20;
9. Copy **Directory (tenant) ID**&#x20;
10. Go to **Certificates & secrets → New client secret**&#x20;
11. Copy generated **Client Secret Value**&#x20;
12. Go to **Authentication**, confirm redirect URI is present&#x20;
13. (Optional) Assign users/groups to the application

### Metadata URL

:::BlockQuote
[**https://login.microsoftonline.com/\{tenant\_id}/v2.0/.well-known/openid-configuration**](https://login.microsoftonline.com/\{tenant_id}/v2.0/.well-known/openid-configuration)
:::

Azure will autofill:

- Authorization URL&#x20;
- Token URL&#x20;
- JWKS&#x20;
- Issuer

## Okta (OIDC)

### Steps in Okta

1. Log in to Okta Admin&#x20;
2. Go to **Applications → Create App Integration**&#x20;
3. Sign-in method: **OIDC**&#x20;
4. Application type: **Web Application**&#x20;
5. Add Sign-in redirect URI:&#x20;
   [****](https://auth.licensespring.com/realms/platform/broker/\{company_code}/endpoint)
6. Sign-out redirect URI optional&#x20;
7. Assign application to users/groups&#x20;
8. Copy:&#x20;
   - Okta domain&#x20;
   - Client ID&#x20;
   - Client Secret

### Metadata URL

:::BlockQuote
https\://\{okta\_domain}/oauth2/default/.well-known/openid-configuration
:::

domain example:

:::BlockQuote
[**https://dev-12345678.okta.com**](https://dev-12345678.okta.com)
:::

## Auth0 (OIDC)

### Steps in Auth0

1. Log in: [**https://manage.auth0.com**](https://manage.auth0.com)
2. Go to **Applications → Applications → Create Application**&#x20;
3. Choose **Regular Web Application**&#x20;
4. Go to **Settings**&#x20;
5. Add to Allowed Callback URLs:&#x20;
   [****](https://auth.licensespring.com/realms/platform/broker/\{company_code}-\{customer_account_code}/endpoint)
6. Add same value to Allowed Logout URLs (optional)&#x20;
7. Copy:&#x20;
   - Domain&#x20;
   - Client ID&#x20;
   - Client Secret&#x20;
8. Save changes&#x20;

### Metadata URL

:::BlockQuote
https\://\{tenant}.auth0.com/.well-known/openid-configuration
:::

Example of tenant:
[**https://dev-123abc45.auth0.com**](https://dev-123abc45.auth0.com)

Add callback URL:

:::BlockQuote
https\://auth.licensespring.com/realms/platform/broker/\{company\_code}/endpoint
:::

## Required OIDC Information

All required metadata is in well known openid configuration which you can import, or you can fill it manually.

## Configuration Steps on platform


Navigate to
&#x20;**Platform → Settings → Customer Accounts -> Single Sign-On**&#x20;

1. Click **Add SSO Provider**&#x20;
2. Select **OpenID Connect (OIDC)**&#x20;
3. Enter the required fields (Client ID, Client Secret, import well known configuration or rarely do it manual)&#x20;
4. Enable (recommended):
   &#x20;**✓ Create new platform user if it does not exist**&#x20;
5. Save the configuration&#x20;
6. Use the SSO login on your next signin

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/YTS4WNMiUKGniGMg6bZkb_image.png)

## Login in to the user portal using SSO

Once you have succesfully added your identity provider to the customer account SSO settings, every license user and license manager assigned to this customer account can continue logging in to the user portal.

User portal URL: [**https://users.licensespring.com**](https://users.licensespring.com)

The SSO login process is the same as for the vendor platform SSO. On a login screen click the **Change Login Method** button and select **Single Sign-on (SSO).**

A prompt will ask for the customer account code and company code. Here, enter those codes you extracted in previous steps.

![SSO Login Without Subdomain](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/9PauYxVqOD_83nMnxAbgq_image.png "SSO Login Without Subdomain")

### User portal subdomains for Enterprise accounts

For **Enterprise accounts**, we host user portal on company code subdomain.This subdomain provides a streamlined experience by removing the requirement for users to manually input their company code during the login process to our user portal.

If you are an Enterprise user, you can access it via: `https://{company_code}.users.licensespring.com`

By navigating to the custom subdomain (e.g., `https://company_code.users.licensespring.com`), users are automatically linked to their respective customer accounts, and they do not need to input customer code - thus simplifying the SSO login flow and enhancing user convenience.



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/IMyXM5rAiQmiowZNM-XOo_image.png)

## License API Authentication

If you plan to use the License API directly to authenticate users using Single Sign-on instead of username/password you need to follow next steps.

### Get Single Sign On Hosted UI URL

The `/api/v4/sso_url` endpoint will return the URL where your hosted login UI will be served. To create the correct URL you need to use `customer_account_code` of the customer account for which the user pool and providers have been created and the `product_short_code` of the product defined in LicenseSpring.

Details for this endpoint are written in the [**Single Sign-On URL**](docId\:QbJwnphsDcS0L25UW6PTq) page. Use the URL from the response to open the hosted UI through which your users can login.

### Extract the `id_token` or `code` from the `redirect_url` and Activate the License

After successful login on the hosted UI, users will be redirected to the URL from `redirect_uri` field. Attached to this page URL you will receive some query parameters, of which the most important is the `id_token` or `code` if you are using authorization code grant described in more detail on the [**Single Sign-On URL**](docId\:QbJwnphsDcS0L25UW6PTq) page.

Along with the `customer_account_code` this field needs to be sent to the [**Activate License (Online Method)**](docId\:Mt2yGm6CJzh2bumU-Gfww) endpoint. License user needs to be assigned before that to the license which is being activated.

:::hint{type="info"}
Our SDKs support SSO license activation natively. Check more details [**here**](https://docs.licensespring.com/sdks/tutorials/advanced-usage/single-sign-on).
:::

If you require assistance or have custom SSO requirements, please contact [**LicenseSpring Support**](https://licensespring.zendesk.com/agent/).


[title] License API changelog
[path] Changelog/

### v4.1.51 (12.02.2026.)

- A fix has been added to `device-variables` feature flag check to skip the check on requests with device variables `{}`

### v4.1.50 (11.02.2026.)

- Implemented company feature flags: `device-variables`, `metadata`, `prevent-vm`, `max-transfers`, `feature-licensing-activation`, `feature-licensing-consumption`, `feature-expiry-date`

### v4.1.49 (04.02.2026.)

- Implemented `/floating/feature_borrow`
- Added `installation_file` object to license and bundle activation (online and offline) responses
- Fixed an error response in license/bundle offline deactivation when consumptions were sent beyond the alotted consumption limit
- Added event logging for consumptions and variables if they're sent in oflfine deactivation
- Added feature flag checks for: `model:consumption`, `model:perpetual`, `model:subscription`, `model:time-limited`, `model:trial`, `model:floating-cloud`
- ``

### v4.1.48 (22.01.2026.)

- Fixed a bug where `user_licenses` performed incorrect product filtering

### v4.1.47 (21.01.2026.)

- Fixed a bug where create order would create licenses with `validity_period` set to "0000-00-00"
- Fixed a bug where `user_licenses` endpoint would not return licenses if the requested product code was a product in a bundle

### v4.1.46 (15.01.2026.)

- Relaxed `variables` validation in deactivation endpoints for legacy compatibility

### v4.1.45 (12.01.2026.)

- Integrated Platform feature flag checks, added checks for permission to create key-based and user-based licenses in create order
- Added support for multiple redirect URIs in SSO
- Fixed a hardware key check bug in activate\_bundle\_offline

### v4.1.44 (17.12.2025.)

- Added SSO user authentication to /floating/borrow endpoint
- Fixed a regression in order creation for bundles where user list on order item level would be ignored
- Fixed a bug where license validity duration and period was incorrectly calculated during activation

:::Changelog{title="v4.1.43 (09.12.2025.)"}
::ChangelogItem{type="fixed" description="Fixed a bug which caused `product_version_not_supported` error to be returned for activations and checks from floating server for licenes with associated installation files"}
:::

:::Changelog{title="v4.1.42 (08.12.2025.)"}
::ChangelogItem{type="fixed" description="Fixed a bug where incorrect license policy was being selected during order creation"}

::ChangelogItem{type="fixed" description="Fixed a bug where transfer limits were being checked for licenses with unlimited activations"}

::ChangelogItem{type="fixed" description="Fixed a bug where the user_licenses response was missing sub-licenses inside of bundles"}
:::

:::Changelog{title="v4.1.39 (25.11.2025.)"}
::ChangelogItem{type="fixed" description="Fixed a bug with parsing non-standard date header strings"}
:::

:::Changelog{title="v4.1.35 (04.11.2025.)"}
::ChangelogItem{type="added" description="Implemented global features and global feature groups"}

::ChangelogItem{type="added" description="Implemented /.well-known endpoint"}

::ChangelogItem{type="fixed" description="Fixed a bug where license template custom fields were being ignored during order creation"}
:::

:::Changelog{title="v4.1.34 (23.10.2025.)"}
::ChangelogItem{type="added" description="Added checks for `company.is_active`"}

::ChangelogItem{type="added" description="Added support for `note` property in licenses in order creation"}

::ChangelogItem{type="fixed" description="Fixed a concurrency bug in order creation"}
:::

:::Changelog{title="v4.1.33 (14.10.2025.)"}
::ChangelogItem{type="added" description="Added event notifications for license.checked and license.released"}

::ChangelogItem{type="added" description="Added floating_in_use_devices property to license response in the following endpoints: check_license, check_bundle, device_licenses, floating/borrow"}

::ChangelogItem{type="fixed" description="Fixed a validation bug for enum custom_fields during order creation"}
:::

:::Changelog{title="v4.1.31 (25.09.2025.)"}
::ChangelogItem{type="added" description="Added support for company-wide schema v2 request enforcement"}
:::

:::Changelog{title="v4.1.30 (16.09.2025.)"}
::ChangelogItem{type="added" description="Added support for schema v2 type requests, with a full-payload signature"}

::ChangelogItem{type="added" description="Added support for non-base64 json to offline activation/deactivation endpoints"}

::ChangelogItem{type="fixed" description="Fixed a bug with customer data not being correctly updated when updating an existing order during order creation"}
:::

:::Changelog{title="v4.1.29 (09.09.2025.)"}
::ChangelogItem{type="added" description="New error mesage for users who are have been temporarily locked out due to too many failed authentications"}

::ChangelogItem{type="fixed" description="Fixed a bug with license checks for Floating Server version 2"}
:::

:::Changelog{title="v4.1.28 (01.09.2025.)"}
::ChangelogItem{type="fixed" description="Fixed a bug with customer metadata being overwritten during order creation when an existing customer was being used"}
:::

:::Changelog{title="v4.1.27 (27.08.2025.)"}
::ChangelogItem{type="added" description="Added `installation_file_id` to all license responses"}

::ChangelogItem{type="added" description="Added `append_product` optional parameter to license webhook endpoint"}

::ChangelogItem{type="added" description="Added a 30 second tolerance to the `borrow_until` check in the `floating/borrow` endpoint to avoid issues with time mismatches between client and server when maximum borrow time is requested"}

::ChangelogItem{type="fixed" description="Fixed a bug where the `trial_created` event would be triggered on non-trial licenses"}
:::

:::Changelog{title="v4.1.26 (18.07.2025.)"}
::ChangelogItem{type="fixed" description="Fixed a bug in order creation where license policies would get mixed up for multiple orders containing different policies with the same policy code"}
:::

:::Changelog{title="v4.1.23 (15.07.2025.)"}
::ChangelogItem{type="added" description="Implemented product feature groups in order creation"}

::ChangelogItem{type="added" description="Added support for product features and custom fields for bundles in order creation"}

::ChangelogItem{type="fixed" description="Fixed a bug with total_activations count for multiple license users sharing the same device"}

::ChangelogItem{type="fixed" description="Fixed a race condition bug in license deactivation"}

::ChangelogItem{type="fixed" description="Fixed a race condition bug in floating borrow and floating release"}
:::

:::Changelog{title="v4.1.22 (17.06.2025.)"}
::ChangelogItem{type="added" description="Implemented `allow_offline_activation` in licenses and license templates"}

::ChangelogItem{type="added" description="Implemented `activation_type` in license devices"}

::ChangelogItem{type="added" description="`openid_configuration` values added to `/sso_url` response"}

::ChangelogItem{type="fixed" description="Fixed a concurrency bug in license activation"}
:::

:::Changelog{title="v4.1.21 (10.06.2025.)"}
::ChangelogItem{type="added" description="Added `company: { id }` field to activation responses"}
:::

:::Changelog{title="v4.1.20 (09.06.2025.)"}
::ChangelogItem{type="fixed" description="Fixed validation for `deactivate_bundle_offline` endpoint"}
:::

:::Changelog{title="v4.1.18 (26.05.2025.)"}
::ChangelogItem{type="added" description="Added webhook events for device variable changes"}

::ChangelogItem{type="added" description="Added `max_activations` for user object in order create endpoint"}

::ChangelogItem{type="added" description="Added `company` object repsonse to all endpoints that return a JSON response"}

::ChangelogItem{type="fixed" description="Fixed a bug with hardware keys when a single key is used accross multiple company accounts"}
:::

:::Changelog{title="v4.1.17 (20.05.2025.)"}
::ChangelogItem{type="added" description="Added support for fixed custom field values in order and trial creation"}

::ChangelogItem{type="added" description="Added `is_expired` to license activation responses"}

::ChangelogItem{type="fixed" description="Fixed missing user info in license activation history"}

::ChangelogItem{type="fixed" description="Fixed `app_ver` parameter being ignored during license activation"}
:::

:::Changelog{title="v4.1.16 (15.05.2025.)"}
::ChangelogItem{type="fixed" description="Fixed license keys being incorrectly assigned to sub-licenses in bundle orders"}
:::

:::Changelog{title="v4.1.15 (08.05.2025.)"}
::ChangelogItem{type="fixed" description="Fixed an incorrect error message for validation errors for JSON payload in offline endpoints"}

::ChangelogItem{type="fixed" description="Fixed notification event max_consumptions_perc_reached"}
:::

:::Changelog{title="v4.1.14 (07.05.2025.)"}
::ChangelogItem{type="added" description="Implemented support for combined bundle and non-bundle orders in a single order creation request"}

::ChangelogItem{type="added" description="Implemented support for licensepring-hardware-key for OAuth requests"}

::ChangelogItem{type="added" description="Added new webhook events license_product_feature.updated and license_custom_field.created"}

::ChangelogItem{type="added" description="Added notification events max_feature_consumptions_reached and max_feature_consumptions_perc_reached "}

::ChangelogItem{type="added" description="Implemented support for installation_file in order creation"}

::ChangelogItem{type="fixed" description="Fixed an incorrect error message for validation errors for JSON payload in offline endpoints"}

::ChangelogItem{type="fixed" description="Fixed notification event max_consumptions_perc_reached"}
:::

:::Changelog{title="v4.1.13 (25.04.2025.)"}
::ChangelogItem{type="fixed" description="Fixed a bug with incorrectly calculated overages for consumptions"}
:::

:::Changelog{title="v4.1.12 (23.04.2025.)"}
::ChangelogItem{type="added" description="Added product_details object to device_licenses endpoint response"}
:::

:::Changelog{title="v4.1.11 (22.04.2025.)"}
::ChangelogItem{type="added" description="Implemented transactionalized license/bundle activation and consumption actions"}

::ChangelogItem{type="added" description="Implemented installation_file_id logic in order webhook"}

::ChangelogItem{type="improved" description="Improved validation schema for order webhook"}
:::

:::Changelog{title="v4.1.10 (17.04.2025.)"}
::ChangelogItem{type="fixed" description="Fixed an issue with check_license containing installation file values from older installation files"}
:::

:::Changelog{title="v4.1.9 (11.04.2025.)"}
::ChangelogItem{type="improved" description="Integrated improved checks for activation and consumption limits"}
:::

:::Changelog{title="v4.1.3 (10.04.2025.)"}
::ChangelogItem{type="fixed" description="Fixed an error on user_licenses endpoint that occured when the optional product parameter was provided"}
:::

:::Changelog{title="v4.1.2 (09.04.2025.)"}
::ChangelogItem{type="fixed" description="Validation hotfix for boolean query parameters written in non-lowercase"}
:::

:::Changelog{title="v4.1.1 (08.04.2025.)"}
::ChangelogItem{type="improved" description="Performance improvements across API"}

::ChangelogItem{type="improved" description="Stricter schema validation across API"}

::ChangelogItem{type="fixed" description="Fixed partial activation of bundle licenses on online and offline bundle activation endpoints"}
:::

:::Changelog{title="v4.0.43 (20.02.2025.)"}
::ChangelogItem{type="improved" description="Error message when creating license device fails"}

::ChangelogItem{type="fixed" description="Offline signature in offline activation response for OAuth payloads"}
:::

:::Changelog{title="v4.0.42 (19.02.2025.)"}
::ChangelogItem{type="added" description="Implemented OAuth functionality"}
:::

:::Changelog{title="v4.0.41 (17.02.2025.)"}
::ChangelogItem{type="fixed" description="Fixed `is_initial_password` not being updated on password change"}
:::

:::Changelog{title="v4.0.40 (10.02.2025.)"}
::ChangelogItem{type="added" description="Implemented `activate_bundle_offline` endpoint"}

::ChangelogItem{type="added" description="Implemented `env` parameter in `check_license` and `product_details` endpoints"}

::ChangelogItem{type="added" description="Implemented `offline_floating_consumptions_sync` event in `add_consumption` and `add_feature_consumption` endpoints"}

::ChangelogItem{type="added" description="Implemented a check for `allow_negative_consumptions` during license deactivation: negative consumption value will not be applied during deactivation if the license does not support negative consumptions"}

::ChangelogItem{type="fixed" description="Fixed `customer_account_id` logic to ensure provided customer and customer_account values are consistent if they already exist in db"}

::ChangelogItem{type="fixed" description="Fixed signature header in `sso_url` to calculate the signature of the entire payload and not just the url string"}

::ChangelogItem{type="improved" description="Improved validation error messages to return expected request payload schema"}
:::

:::Changelog{title="v4.0.39 (23.01.2025.)"}
::ChangelogItem{type="added" description="Integrated customer account association for orders using `customer_account_id` and `add_to_customer_account` in order webhook"}
:::

:::Changelog{title="v4.0.37 (13.01.2025.)"}
::ChangelogItem{type="fixed" description="Fixed missing user fields in license responses"}
:::

:::Changelog{title="v4.0.36 (08.01.2025.)"}
::ChangelogItem{type="fixed" description="Fixed an error in the add_consumption endpoint"}
:::

:::Changelog{title="v4.0.35 (08.01.2025.)"}
::ChangelogItem{type="added" description="Implemented keycloak integration in all API endpoints"}

::ChangelogItem{type="improved" description="Optimized license webhook key generation"}
:::

:::Changelog{title="v4.0.34 (12.12.2024.)"}
::ChangelogItem{type="added" description="Implemented `products` endpoint"}

::ChangelogItem{type="added" description="Implemented `device_licenses` endpoint"}

::ChangelogItem{type="added" description="Implemented `activate_bundle` endpoint"}

::ChangelogItem{type="improved" description="`product` parameter made optional in `user_licenses` endpoint"}
:::

:::Changelog{title="v4.0.33 (28.11.2024.)"}
::ChangelogItem{type="added" description="Implemented SSO authentication on `get user licenses` endpoint"}

::ChangelogItem{type="fixed" description="Fixed incorrect error message in `get user licenses` endpoint when authentication data is correct but user is not assigned to requested product"}

::ChangelogItem{type="fixed" description="Fixed handling customer ID in order create webhook"}

::ChangelogItem{type="fixed" description="Added missing `allow_negative_consumptions` property to feature consumption endpoint"}
:::

:::Changelog{title="v4.0.32 (20.11.2024.)"}
::ChangelogItem{type="fixed" description="Fixed a bug in order creation where customer.id could be manually overriden in the request data"}
:::

:::Changelog{title="v4.0.31 (31.10.2024.)"}
::ChangelogItem{type="fixed" description="Fixed a bug where trial_days field was missing in license activation response for licenses with enabled trial"}

::ChangelogItem{type="fixed" description="Fixed a bug where allow_negative_consumptions field was missing on consumption license response"}
:::

:::Changelog{title="v4.0.30 (09.10.2024.)"}
::ChangelogItem{type="improved" description="Expanded validation for order create endpoint to ensure top-level product is a bundle and fields specific to key/user-based licenses can only be sent with the appropriate license type"}

::ChangelogItem{type="fixed" description="Fixed a bug where floating slots could be reserved with an expired license"}

::ChangelogItem{type="fixed" description="Fixed a bug where a license with multiple activations and no device transfers could only be activated once"}

::ChangelogItem{type="fixed" description="Fixed a bug where negative feature consumptions could be sent for a license where feature consumptions did not allow negative values"}
:::

:::Changelog{title="v4.0.29 (19.09.2024.)"}
::ChangelogItem{type="added" description="Implemented support for consumption notifications when consumption amount passes thresholds defined by notification policies"}

::ChangelogItem{type="added" description="Implemented the alphabet parameter in the key generator which allows specifying which characters are used to generate license keys"}

::ChangelogItem{type="added" description="Added trial notifications for trial licenses during order creation"}

::ChangelogItem{type="added" description="Implemented support for negative consumptions and license policies allowing negative consumptions"}

::ChangelogItem{type="improved" description="Reworked device count to avoid problems with devices being incorrectly enumerated after license reset"}

::ChangelogItem{type="improved" description="Improved calculating total activations, consumptions and transfers to avoid a concurrency bug when a large number of concurrent requests occured on the same license"}

::ChangelogItem{type="fixed" description="Fixed a bug where license keys were being generated on user-based licenses"}

::ChangelogItem{type="fixed" description="Fixed a bug where floating borrow was allowed using expired licenses"}
:::

:::Changelog{title="v4.0.28 (29.08.2024.)"}
::ChangelogItem{type="added" description="Expanded order creation endpoint to allow for more flexible parameter overriding and setting initial values when creating bundle orders"}

::ChangelogItem{type="added" description="Added check for allowed license types when creating bundle orders"}

::ChangelogItem{type="fixed" description="Fixed filtering by licenseID for bundle orders"}

::ChangelogItem{type="fixed" description="Fixed incorrect password validation in user_licenses endpoint"}

::ChangelogItem{type="fixed" description="Fixed a bug in request validation schema"}
:::

:::Changelog{title="v4.0.27 (25.07.2024.)"}
::ChangelogItem{type="added" description="Added `user_licenses` endpoint to return a list of licenses for a given user"}

::ChangelogItem{type="added" description="Added `license_id` parameter as an optional filter to all endpoints that work with licenses"}

::ChangelogItem{type="fixed" description="Fixed a bug in request validation schema"}
:::

:::Changelog{title="v4.0.26 (27.06.2024.)"}
::ChangelogItem{type="added" description="Added `validity_period` attribute to license policies"}

::ChangelogItem{type="fixed" description="Fixed a bug that would fetch the incorrect license when activating/deactivating user-based bundle licenses without a provided bundle code"}

::ChangelogItem{type="fixed" description="Fixed a bug causing duplicate IDs during order creation in the order webhook"}
:::

:::Changelog{title="v4.0.25 (24.06.2024.)"}
::ChangelogItem{type="fixed" description="Fixed an error message being returned while activating trial license for user-based licenses"}
:::

:::Changelog{title="v4.0.24 (21.06.2024.)"}
::ChangelogItem{type="added" description="Added support for optional `policy_code` parameter to order webhook"}

::ChangelogItem{type="added" description="Added support for device variables in activation payloads for activate_license and activate_offline endpoints"}

::ChangelogItem{type="added" description="Added optional `key_length` parameter to license webhook to allow for increased license key length"}

::ChangelogItem{type="improved" description="Improved key generator by increasing cap for maximum number of keys generated per request to 10.000"}

::ChangelogItem{type="fixed" description="Fixed a bug where a user with multiple user-based bundle licenses could not activate the correct license"}

::ChangelogItem{type="fixed" description="Restored the missing `address` field in license customer info"}
:::

:::Changelog{title="v4.0.23 ( 04.06.2024. )"}
::ChangelogItem{type="added" description="Added support for `licensepring-hardware-key` in offline license payloads"}

::ChangelogItem{type="added" description="Added optional `include_metadata_string` parameter to endpoints to return `metadata` values as serialized JSON strings in `metadata_string`"}
:::

:::Changelog{title="v4.0.22 ( 21.05.2024. )"}
::ChangelogItem{type="improved" description="Added `is_air_gapped` field to license activation and check response"}

::ChangelogItem{type="added" description="Added support for `licensespring-hardware-key` header"}
:::

:::Changelog{title="v4.0.21 ( 06.05.2024. )"}
::ChangelogItem{type="fixed" description="Fixed sending `max_consumption` to license feature consumption analytics"}
:::

:::Changelog{title="v4.0.20 ( 23.04.2024. )"}
::ChangelogItem{type="added" description="Added `trial_days` to license response on check_license if license is in trial"}

::ChangelogItem{type="added" description="Added support for `enabled` field on create_order logic"}
:::

:::Changelog{title="v4.0.19 ( 02.04.2024. )"}
::ChangelogItem{type="added" description="Added `bundle_code` for user based bundle licenses"}
:::

:::Changelog{title="v4.0.18 ( 19.03.2024. )"}
::ChangelogItem{type="added" description="Added license events for Events API"}

::ChangelogItem{type="added" description="Add `disabled_product` and `archived_product` to the list of errors"}

::ChangelogItem{type="improved" description="Expanded customer Events API data"}
:::

:::Changelog{title="v4.0.17 ( 06.03.2024. )"}
::ChangelogItem{type="added" description="Added support for `customer.updated` event"}

::ChangelogItem{type="improved" description="Improved date header verification"}
:::

:::Changelog{title="v4.0.16 ( 21.02.2024.)"}
::ChangelogItem{type="improved" description="Metadata can be set both as a JSON string literal and JSON object format."}

::ChangelogItem{type="added" description="Metadata returned inside offline activation response"}
:::

:::Changelog{title="v4.0.15 ( 06.02.2024.)"}
::ChangelogItem{type="added" description="Added support for `webhooks`"}
:::

:::Changelog{title="v4.0.13 (09.12.2023.)"}
::ChangelogItem{type="added" description="Added `include_expired_feature` to `check_license` endpoint"}

::ChangelogItem{type="fixed" description="Fixed activating user based product bundle licenses"}
:::

:::Changelog{title="v4.0.11 (21.11.2023.)"}
::ChangelogItem{type="improved" description="Added `include_latest_version` and `include_custom_fields` to `product_details` endpoint"}
:::

:::Changelog{title="v4.0.10 (07.11.2023)"}
::ChangelogItem{type="improved" description="Implemented floating cloud license features"}

::ChangelogItem{type="fixed" description="Remove `extra` field from analytics activity"}
:::

:::Changelog{title="v4.0.8 (18.09.2023.)"}
::ChangelogItem{type="added" description="Using `integrations` table to support Stripe integration"}

::ChangelogItem{type="fixed" description="Fixed saving anayltics data when `trial_key` request fails"}

::ChangelogItem{type="fixed" description="Fixed parsing `os_ver` and `mac_address` query params"}
:::

:::Changelog{title="v4.0.7 (07.09.2023.)"}
::ChangelogItem{type="improved" description="Deployment improvements"}
:::

:::Changelog{title="v4.0.6 (27.07.2023.)"}
::ChangelogItem{type="fixed" description="Fixed keygen timeouts on large number of concurrent keygen requests"}
:::

:::Changelog{title="v4.0.4 (06.07.2023.)"}
::ChangelogItem{type="improved" description="Return error message on order create if `license users` contains a higher number of users than `max_license_users` allow"}

::ChangelogItem{type="fixed" description="Fixed `customer_license_users` endpoint and `product` query param filter"}
:::

:::Changelog{title="v4.0.3 (21.06.2023.)"}
::ChangelogItem{type="fixed" description="Ignore `validity_period` if perpetual and consumption type licenses are not in trial"}
:::

:::Changelog{title="v4.0.2 (19.06.2023.)"}
::ChangelogItem{type="improved" description="Optimization to the deployment process"}

::ChangelogItem{type="fixed" description="Fixed logger invocation when activating an expired trial license"}

::ChangelogItem{type="fixed" description="Use fallback when default license policy not assigned"}
:::

:::Changelog{title="v4.0.1 (13.06.2023.)"}
::ChangelogItem{type="fixed" description="Added fallback in unlikely case that a product does not have a default license policy"}

::ChangelogItem{type="fixed" description="Fixed `validity_period` response on activated licenses"}

::ChangelogItem{type="fixed" description="Added `validity_period` check on all trial licenses"}

::ChangelogItem{type="improved" description="`metadata` is returned inside `product_details` object when doing license check and activation"}

::ChangelogItem{type="improved" description="Update internal sentry handler"}

::ChangelogItem{type="added" description="Added metadata JSON field on customers, orders, licenses, products and product features"}

::ChangelogItem{type="added" description="Implemented `pm2` process management tool"}

::ChangelogItem{type="improved" description="Optimized license fetching SQL query"}
:::

:::Changelog{title="v4.0.0 ()"}
::ChangelogItem{type="improved" description="Replaced Express with Fastify"}

::ChangelogItem{type="improved" description="Updated all internal libraries to the latest version"}

::ChangelogItem{type="improved" description="All api methods rewritten from callbacks to async/await syntax"}
:::

:::Changelog{title="28.02.2023"}
::ChangelogItem{type="fixed" description="max_activations on /trial_key endpoint changed so that it is inherited from license policy with 1 as a default"}

::ChangelogItem{type="fixed" description=" Fixed customer_does_not_exist error format"}
:::

:::Changelog{title="02.02.2023"}
::ChangelogItem{type="fixed" description="fix: When creating customer api will trim emails and remove whitespaces"}

::ChangelogItem{type="added" description=" Docs for new Mgmt API endpoint "}
:::

:::Changelog{title="17.01.2023."}
::ChangelogItem{type="added" description="Added grace_period and allow_grace_period to licenses and license policy"}

::ChangelogItem{type="added" description="Extended License api/shared keys - multiple api/shared keys per account, allowed products option, labels, read_only and revoked fields."}

::ChangelogItem{type="fixed" description="Handle failed attempt when creating subscriptions using Stripe checkout"}

::ChangelogItem{type="improved" description="Expand expiration check with grace_period"}
:::

:::Changelog{title="20.12.2022."}
::ChangelogItem{type="added" description="Support for adhoc intervalUnit"}
:::

:::Changelog{title="06.12.2022."}
::ChangelogItem{type="improved" description="Expand extra field on AnalyticsActivity model to send additional details in JSON"}

::ChangelogItem{type="improved" description="Added allow_unlimited_activations and allow_unlimited_consumptions to the data model"}

::ChangelogItem{type="improved" description=" Added Date header validation"}
:::

:::Changelog{title="22.11.2022."}
::ChangelogItem{type="fixed" description="always return device_id on license activation response as Integer"}

::ChangelogItem{type="improved" description="Order webhook returns new order_items in response"}
:::

:::Changelog{title="22.11.2022."}
::ChangelogItem{type="fixed" description="always return device_id on license activation response as Integer"}

::ChangelogItem{type="improved" description="Order webhook returns new order_items in response"}
:::

:::Changelog{title="04.11.2022."}
::ChangelogItem{type="fixed" description="times_activated value on a License cannot be set lower than 0 on license deactivation"}

::ChangelogItem{type="improved" description="Added min validation on times_activated field on the License model"}
:::

:::Changelog{title="20.9.2022."}
::ChangelogItem{type="improved" description="Allowed Authorization code grant for SSO"}

::ChangelogItem{type="improved" description=" Sending LicenseSignature header on license check and activation"}

::ChangelogItem{type="improved" description=" Attaching license_signature_v2 to offline activation response object"}

::ChangelogItem{type="fixed" description="Consumptions events use max_consumptions field instead of max_overages to send events"}
:::

:::Changelog{title="30.08.2022."}
::ChangelogItem{type="improved" description="Expanded consumptions events inside Usage Report with additional data"}

::ChangelogItem{type="improved" description="  Added Max consumptions reached and Max feature consumptions reached Usage report events"}

::ChangelogItem{type="improved" description="Support for sending license_policy code when creating ordeobject"}

::ChangelogItem{type="improved" description="Attached user object tot the offline activation response"}
:::

:::Changelog{title="17.07.2022."}
::ChangelogItem{type="fixed" description="License deactivation decrements total_activations field on license user"}

::ChangelogItem{type="added" description="  Added new custom attribute is_single_license"}

::ChangelogItem{type="improved" description=" Implemented max_activations on license users"}
:::

:::Changelog{title="05.07.2022."}
::ChangelogItem{type="fixed" description="Restrict setting invalid license type values"}

::ChangelogItem{type="added" description="  Implement feature consumption analytics activity"}
:::

:::Changelog{title="14.06.2022."}
::ChangelogItem{type="fixed" description="Restrict setting invalid license type values"}

::ChangelogItem{type="added" description="  Implement feature consumption analytics activity"}
:::

:::Changelog{title="24.05.2022."}
::ChangelogItem{type="improved" description="license check and activation response expanded with can_borrow and max_borrow_time"}

::ChangelogItem{type="fixed" description="  floating/borrow endpoint sets the device as floating_in_use if slots available&#xA;improvement: Support for product bundles on all endpoints"}
:::

:::Changelog{title="10.05.2022."}
::ChangelogItem{type="added" description="Add borrowed_until field to license check response and clear the borrowed_until device field on floating release"}

::ChangelogItem{type="improved" description=" /floating/release endpoint changes borrowed_until on device to null"}

::ChangelogItem{type="fixed" description="Fix borrow_until field in floating_borrow endpoint"}
:::

:::Changelog{title="26.4.2022."}
::ChangelogItem{type="improved" description="Add is_borrowed field to the the license check"}

::ChangelogItem{type="improved" description=" Fix creating duplicate license devices on batch license activation requests with unique license_id+hwid constraint"}

::ChangelogItem{type="improved" description="Send notification request on license activation"}

::ChangelogItem{type="improved" description="Added api/v4/floating/borrow endpoint and floating_borrow analytics activity event"}
:::

:::Changelog{title="29.3.2022."}
::ChangelogItem{type="improved" description=" Expand floating watchdog to handle license borrowing"}

::ChangelogItem{type="fixed" description=" Fixed 2checkout error handler when wrong product code is sent"}

::ChangelogItem{type="improved" description="Extend data model to enable license borrowing"}
:::

:::Changelog{title="15.03.2022."}
::ChangelogItem{type="improved" description="Fixed sso error format"}

::ChangelogItem{type="fixed" description=" Added new /get_device_variables endpoint"}

::ChangelogItem{type="improved" description=" Analytics activity expanded with single_sign_on and get_device_variables events"}
:::

:::Changelog{title="1.3.2022."}
::ChangelogItem{type="improved" description="Fixed max_transfers logic"}

::ChangelogItem{type="fixed" description=" Fixed trial_key analytics action"}

::ChangelogItem{type="improved" description="Handle prevent device transfer value on max_transfers"}

::ChangelogItem{type="improved" description="Accept Single Sign On id_token and customer_account_code params on license_activation endpoint"}

::ChangelogItem{type="improved" description="Created SSO authentication method"}

::ChangelogItem{type="improved" description="Added new api/v4/sso_url for generating AWS Cognito Single Sign On url for enabled customer accounts"}

::ChangelogItem{type="improved" description="Added SSO id_token validation method"}

::ChangelogItem{type="improved" description="Enable sending customer with id only when creating order"}
:::

:::Changelog{title="15.02.2022."}
::ChangelogItem{type="improved" description="Return start_date field in license response on license check and license activation requests"}

::ChangelogItem{type="improved" description=" Add start_date on the License model and return error if license activation attempted before this date"}

::ChangelogItem{type="improved" description="Extend trial_key endpoint with optional license_policy query param and assign first_name, last_name and phone_number to the license user if available"}
:::

:::Changelog{title="01.02.2022."}
::ChangelogItem{type="improved" description="Replace deprecated requests library"}

::ChangelogItem{type="fixed" description="fastspring: Fix timeout with related offe"}

::ChangelogItem{type="improved" description="stripe: Support license_policy price attribute ( enable using custom_fields and product_features )"}
:::

:::Changelog{title="18.01.2022."}
::ChangelogItem{type="improved" description="Expand company settings with allow_offline_floating_cloud"}
:::

:::Changelog{title="05.01.2022."}
::ChangelogItem{type="fixed" description="Prevent floating_cloud licenses to be activated offline"}

::ChangelogItem{type="improved" description="Deprecated order and license webhooks"}

::ChangelogItem{type="improved" description="Added allow_trial and trial_days fields to license template"}
:::

:::Changelog{title="23.12.2021."}
::ChangelogItem{type="improved" description="FastSpring: Update max_activations along floating_users on subscription update when floating_users_from_quantity attribute is present"}
:::

:::Changelog{title="16.11.2021."}
::ChangelogItem{type="improved" description="Add CustomerAccount to the model and return customer_account if available"}

::ChangelogItem{type="improved" description="Append total_consumptions when deactivating offlin"}
:::

:::Changelog{title="03.11.2021."}
::ChangelogItem{type="improved" description="Added is_initial_password and phone_number to the user object on license check and activation"}
:::

:::Changelog{title="19.10.2021."}
::ChangelogItem{type="fixed" description="Added JSON validation on track_device_variables endpoint"}

::ChangelogItem{type="improved" description="Return error on trial_key if product does not allow trial"}

::ChangelogItem{type="improved" description="Expand installation file on license check"}

::ChangelogItem{type="fixed" description="Use true email inside user object on license check"}
:::

:::Changelog{title="06.10.2021."}
::ChangelogItem{type="improved" description="Return overages with product features on license check and activation"}
:::

:::Changelog{title="22.09.2021."}
::ChangelogItem{type="improved" description="Fastspring: Expand subscription.updated event logic to handle changing custom fields, product features and adding new licenses to the order"}
:::

:::Changelog{title="07.09.2021."}
::ChangelogItem{type="improved" description=" License API extended with license policiesr"}
:::

:::Changelog{title="1.09.2021"}
::ChangelogItem{type="improved" description="Floating slots check removed from license activation"}

::ChangelogItem{type="fixed" description="fastspring: Fix subscription.updated handler when floating_users_from_quantity attribute"}

::ChangelogItem{type="added" description="fastspring: Add assign_customer_as_user attribute"}

::ChangelogItem{type="added" description="stripe: Add is_license_manager attribute"}

::ChangelogItem{type="fixed" description="Fixed Order classMethod"}
:::

:::Changelog{title="27.07.2021"}
::ChangelogItem{type="improved" description="Offline deactivation file expanded to support license and license features consumptions update"}
:::

:::Changelog{title="08.07.2021"}
::ChangelogItem{type="improved" description="Added channel field to installation_file and expanded /installation_file endpoint with remaining fields"}

::ChangelogItem{type="fixed" description="Removed license_user_id from the Device"}

::ChangelogItem{type="fixed" description="stripe: Fixed customer.subscription.updated and customer.subscription.deleted events"}
:::

:::Changelog{title="08.07.2021"}
::ChangelogItem{type="improved" description="Added channel field to installation_file and expanded /installation_file endpoint with remaining fields"}

::ChangelogItem{type="fixed" description="Removed license_user_id from the Device"}

::ChangelogItem{type="fixed" description="stripe: Fixed customer.subscription.updated and customer.subscription.deleted events"}
:::

:::Changelog{title="22.06.2021"}
::ChangelogItem{type="improved" description="Created ping endpoint"}

::ChangelogItem{type="improved" description="Implemented license_user_id to the Device"}
:::

:::Changelog{title="22.06.2021"}
::ChangelogItem{type="improved" description="Created ping endpoint"}

::ChangelogItem{type="improved" description="Implemented license_user_id to the Device"}
:::

:::Changelog{title="15.06.2021"}
::ChangelogItem{type="improved" description="Added license_user_id to Device"}

::ChangelogItem{type="fixed" description="Stripe: Fixed subscription renewals"}

::ChangelogItem{type="improved" description="Added new analytics actions and expanded with status code"}
:::

:::Changelog{title="09.06.2021."}
::ChangelogItem{type="improved" description="Expand check_license response with is_floating field"}
:::

:::Changelog{title="01.06.2021."}
::ChangelogItem{type="improved" description="Add initial_password to the trial_key response and fix assignUser method"}
:::

:::Changelog{title="18.05.2021."}
::ChangelogItem{type="improved" description="Fastspring: Add is_license_manager custom attribute to set customer as manager"}

::ChangelogItem{type="improved" description="Fix transfer_count logic and implement max_transfers"}

::ChangelogItem{type="fixed" description="Fix generating signature on license_check response (use ISO string format)"}

::ChangelogItem{type="improved" description="Created customer_license_users endpoint to list all license_users on all orders on some customer"}
:::

:::Changelog{title="11.05.2021."}
::ChangelogItem{type="fixed" description="Added signature to license_check response"}

::ChangelogItem{type="improved" description="Expand /installation_file and /versions endpoint responses with release_date field, add env query param and return only versions and files with release date less than maintenance_period or validity_period of the license"}

::ChangelogItem{type="improved" description="Add requires_version field on installation files"}

::ChangelogItem{type="improved" description=" Add overages and consumption resets on product features"}

::ChangelogItem{type="fixed" description="stripe: Fixed checking for a subscription id"}

::ChangelogItem{type="improved" description="Create order_users endpoint to list all license_users on some order"}
:::

:::Changelog{title="28.04.2021"}
::ChangelogItem{type="fixed" description="Fix installation_file fields on license_check response"}

::ChangelogItem{type="fixed" description="Fix sending emails on user/manager assign"}

::ChangelogItem{type="improved" description="stripe: Fix setting subscription as trial - use trial_end and trial_start fields"}

::ChangelogItem{type="improved" description=" Include order_store_id to license check response"}

::ChangelogItem{type="improved" description="Save event data from integrations ( FastSpring, Stripe ) to LicenseHistory data field"}

::ChangelogItem{type="improved" description="Fix License activation usage report when source is sdk"}
:::

:::Changelog{title="20.04.2021."}
::ChangelogItem{type="fixed" description="Create initial password for new users on trial licenses"}

::ChangelogItem{type="added" description="stripe: Add assign_customer_as_user custom attribute"}

::ChangelogItem{type="improved" description="stripe: Expand Stripe integration to receive trialing status and to respond on customer.subscription.updated event (# 24047525)"}

::ChangelogItem{type="improved" description=" Added floating_in_use_devices in license check response"}
:::

:::Changelog{title="13.04.2021."}
::ChangelogItem{type="added" description="Fastspring: Implemented subscription.updated event handling for single licenses"}

::ChangelogItem{type="added" description="Added license_key in check_license response"}

::ChangelogItem{type="added" description="Fastspring: Added custom attribute floating_users_from_quantity"}
:::

:::Changelog{title="06.04.2021."}
::ChangelogItem{type="fixed" description=" Attach device id to the updated license device on activation to fix missing device id bug"}
:::

:::Changelog{title="30.03.2021."}
::ChangelogItem{type="improved" description=" Expand license activation response with license_key and product_details"}

::ChangelogItem{type="improved" description="Send order reference when creating an order"}

::ChangelogItem{type="fixed" description="Fix getting installation files for user based products"}
:::

:::Changelog{title="23.03.2021."}
::ChangelogItem{type="improved" description="Implement license floating timeout value"}

::ChangelogItem{type="fixed" description="Add consumption fields to offline activation response if license is consumption type"}

::ChangelogItem{type="added" description="fastspring: Added support for trial subscriptions"}

::ChangelogItem{type="added" description="fastspring: Added support for setting custom fields on licenses"}

::ChangelogItem{type="improved" description="Implemented transfer_count on licenses and add new DeviceActivationHistory table"}

::ChangelogItem{type="fixed" description="Check license validity_period on license_activation"}
:::

:::Changelog{title="09.03.2021."}
::ChangelogItem{type="improved" description="Stripe: Get products from the database"}

::ChangelogItem{type="fixed" description="Fixed verification of user based offline license signature"}

::ChangelogItem{type="added" description="Added new LicenseHistory events: License activated, License deactivated, Consumption added, Feature consumption added, Floating release, Offline license activated, Offline license deactivated"}
:::

:::Changelog{title="02.03.2021."}
::ChangelogItem{type="improved" description="use StripeEvent table to check for duplicate Stripe event"}

::ChangelogItem{type="improved" description="added optional allow_overages and max_overages request query params to add_consumption endpoint"}

::ChangelogItem{type="added" description="Stripe: implemented v1 of stripe LicenseSpring integration"}
:::

:::Changelog{title="16.02.2021."}
::ChangelogItem{type="added" description="Implement time-limited product features using expiry_date field"}

::ChangelogItem{type="fixed" description=" Prevent creating duplicate customers when using getTrialLicense webhook with same email address"}
:::

:::Changelog{title="09.02.2021."}
::ChangelogItem{type="added" description="Prevent creating duplicate product features on order create"}

::ChangelogItem{type="added" description=" subscriptions: log SQL query when prolonging license"}

::ChangelogItem{type="added" description="Fastspring: support for creating floating cloud licenses using custom attribute floating_cloud (int)"}

::ChangelogItem{type="fixed" description="Fastspring: fix setting validity_period on subscription prolong - event type subscription.charge.completed&#xA;fix: properly set max_overages as unlimited when 0 is sent as a value"}

::ChangelogItem{type="fixed" description="send consumption_period and reset_consumption fields inside license activation and license check response payload"}

::ChangelogItem{type="added" description="Add requestID to newRelic attributes"}

::ChangelogItem{type="fixed" description="Fix failing LicenseHistory in check"}

::ChangelogItem{type="fixed" description="timeout on invalid call to webhook/license"}
:::

:::Changelog{title="1.12.2020."}
::ChangelogItem{type="fixed" description="intermittent issues with webhook/order"}

::ChangelogItem{type="fixed" description="  fastspring contextual - subscription.deactivated fix"}

::ChangelogItem{type="fixed" description="implemented support for duration in weeks (fastspring contextual and in general))"}

::ChangelogItem{type="improved" description="updated Licenses model with note property and using it in v4 post order on item for license db storage."}

::ChangelogItem{type="fixed" description="extended existing snowflake algorithm with magic number randomness."}

::ChangelogItem{type="added" description="api/v4/versions returns only enabled versions."}

::ChangelogItem{type="added" description="api/v4/activate_license and api/v4/check_license for user-based license returns user object with email, first_name and last_name properties"}

::ChangelogItem{type="fixed" description="offline_activation additional headers saved to license device (app_ver, sdk_ver, ip_local, ...) license_activation and license_check - in case user has more then one license, using not the first but the last one from the database for activation / checkOrder"}

::ChangelogItem{type="added" description="api/v4/change_password user_email API parameter renamed to password and old_password API parameter to password"}

::ChangelogItem{type="added" description="api/v4/change_password implemented"}
:::

:::Changelog{title="1.12.2020."}
::ChangelogItem{type="fixed" description="intermittent issues with webhook/order"}

::ChangelogItem{type="fixed" description="  fastspring contextual - subscription.deactivated fix"}

::ChangelogItem{type="fixed" description="implemented support for duration in weeks (fastspring contextual and in general))"}

::ChangelogItem{type="improved" description="updated Licenses model with note property and using it in v4 post order on item for license db storage."}

::ChangelogItem{type="fixed" description="extended existing snowflake algorithm with magic number randomness."}

::ChangelogItem{type="added" description="api/v4/versions returns only enabled versions."}

::ChangelogItem{type="added" description="api/v4/activate_license and api/v4/check_license for user-based license returns user object with email, first_name and last_name properties"}

::ChangelogItem{type="fixed" description="offline_activation additional headers saved to license device (app_ver, sdk_ver, ip_local, ...) license_activation and license_check - in case user has more then one license, using not the first but the last one from the database for activation / checkOrder"}

::ChangelogItem{type="added" description="api/v4/change_password user_email API parameter renamed to password and old_password API parameter to password"}

::ChangelogItem{type="added" description="api/v4/change_password implemented"}
:::

:::Changelog{title="16.7.2020"}
::ChangelogItem{type="added" description="support for floating on-prem in /webhook/order"}

::ChangelogItem{type="fixed" description=" fix issue with assigning user licenses in /webhook/order"}

::ChangelogItem{type="added" description="allow setting maintenance_period on webhook/order"}

::ChangelogItem{type="improved" description="date is not a required header element on authorization (to support electron.js)"}
:::

:::Changelog{title="24.6.2020."}
::ChangelogItem{type="fixed" description="Fixed license type on trial_key API. Previously the trial_key API was issuing trial keys that were perpetual. It now uses the default license type for which the product was configured."}
:::

:::Changelog{title="23.6.2020."}
::ChangelogItem{type="added" description="New error message: license_key_exists error when webhook/order receives an order with an existing license key"}

::ChangelogItem{type="fixed" description="Fixed consumption features assignment on webhook/order"}

::ChangelogItem{type="fixed" description="Fixed assignment of trial_days on trial_key API. It was previously defaulting to 30 day trial duration on perpetual licenses. Trial keys are now issued with the default trial duration as configured with the product."}
:::

:::Changelog{title="18.6.2020"}
::ChangelogItem{type="added" description="Added the ability to set the value of custom_fields on webhook/order"}

::ChangelogItem{type="added" description="Changed value of the custom field value to be a TEXT"}

::ChangelogItem{type="fixed" description="Fixed trial key validity period when set explicitly through webhook/order"}

::ChangelogItem{type="fixed" description="Fixed times_activated on activate_license API"}
:::

:::Changelog{title="29.04.2020"}
::ChangelogItem{type="added" description="API added max_consumptions to response of api/v4/add_feature_consumption"}
:::

:::Changelog{title="08.04.2020"}
::ChangelogItem{type="added" description="API webhook: fixes to 2checkout key generation"}
:::

:::Changelog{title="03.04.2020"}
::ChangelogItem{type="added" description="API webhook/order - user-based licenses now assign users"}

::ChangelogItem{type="added" description="Implemented overages"}

::ChangelogItem{type="added" description="Added allow_overages, max_overages, reset_consumption and consumption_period to product and license UI"}

::ChangelogItem{type="added" description="API webhook/order - support for consumption overages implemented"}

::ChangelogItem{type="added" description="API max_overages and allow_overages implemented into v4/add_consumption"}
:::

:::Changelog{title="30.3.2020."}
::ChangelogItem{type="added" description="API sending max_consumption(s) on add_feature_consumption and add_consumption endpointss"}
:::

:::Changelog{title="4.12.2019."}
::ChangelogItem{type="added" description="API added times_activated and max_activations on check_license and activate_license endpoints"}

::ChangelogItem{type="fixed" description="BUG on API: fix license_custom_field API response"}
:::


[title] Upload offline license file
[path] Floating Server/Floating Server V1/API Reference/license/

{
  "id": "GIf4D6DbMuswo2hwDvZXM",
  "data": {
    "url": "http://localhost:8080/api/v4/license/upload",
    "name": "Upload offline license file",
    "method": "POST",
    "request": {
      "pathParameters": [],
      "queryParameters": [],
      "headerParameters": [],
      "bodyDataParameters": [],
      "formDataParameters": []
    },
    "responses": [
      {
        "isExpanded": true,
        "statusCode": "200",
        "description": "OK",
        "jsonExample": ""
      }
    ],
    "contentType": "multipart/form-data"
  },
  "type": "api-oas-v2",
  "children": [
    {
      "text": ""
    }
  ]
}
[title] FastSpring Classic Store
[path] Integrations/FastSpring/

:::hint{type="danger"}
We are no longer maintaining and testing our integration with FastSpring classic.
:::

:::hint{type="info"}
These are instructions for our new platform. For customers still using the old platform (if you log in from app.licensespring.com), please contact customer support for instructions on integrating with FastSpring.
:::

## Configure License Fulfillment Through FastSpring

*Duration*: 15 minutes

There are 3 parts to the configuration within FastSpring.

1. When creating a product, you need to set up product name to match code in LicenseSpring
2. You will need to configure the license generation within your product.
3. Finally, you will need to configure the post-order notifications.

### 1. Configuring Your Product

There is only one thing here - "Product name" needs to match the "short-code" in LicenseSpring:

![Inputting Product Name](https://kwiki-user-media.s3.amazonaws.com/content/image_widgets/Screenshot_2019-04-05_at_15.02.40.png "Inputting Product Name")

### 2. Adding License Generation to Your Product

Login to your FastSpring account.
Navigate to the product you are configuring (click on the Store > Products and Pages > \[Product name].
Beside “Fulfillment Actions” Click “Add Fulfillment”.
Click “Generate a License” > Remote Server Request.

![Select Remote Server Request](https://kwiki-user-media.s3.amazonaws.com/content/image_widgets/gs_image_4.png "Select Remote Server Request")

Fill out the fields in the next step with the following information:

- URL: [`https://api.licensespring.com/api/fast_license`](https://api.licensespring.com/api/fast_license)
- Method: HTTP POST
- POST Encoding: UTF-8
- Output Format: Single-Line License (Quantity based)

Click “Create”.

![Filling License Generation Fields](https://kwiki-user-media.s3.amazonaws.com/content/image_widgets/Screenshot_2019-04-05_at_14.59.01.png "Filling License Generation Fields")

### UUID parameter

:::hint{type="warning"}
Under the "Product Fulfillment" section, in the "Parameters" tab, it's important to input the UUID (Universally Unique Identifier) in order for the system to function correctly and generate the license. The UUID serves as a unique identifier that is essential for the product fulfillment process to work as expected and to ensure that the generated licenses are associated with the correct company.
:::

Find your \`uuid\` inside FastSpring integration configuration view under Settings -> Integrations \[tab]:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/w-lJ-qn47WOLxw_dvWdZq_scr-20231107-kdla.png)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/9gsK47wFuzUc6jaOEaWI__image.png "Edit product fullfilment")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/j8o7s_B8f6ITlnvF-rlWZ_image.png "Paramater tab to add required uuid")

### 3. Add Order Webhook Notification

Next, you'll need to configure the post-order notification:
Click on “Notifications” in the top right corner.

![Figure 7 - Notifications](https://kwiki-user-media.s3.amazonaws.com/content/image_widgets/gs_image_7.png "Figure 7 - Notifications")

Add a “custom notification”.

In the next step, use the following information to configure the custom post-order notification:

- Event Type: Order Completed
- Destination: HTTP URL
- Applicable Site: the name of the store for which you are configuring the product for
- Liver Server URL: [`https://api`](https://api.licensespring.com/api/fast_post_order)[`.licensespring.com/api/fast_post_order`](https://api.licensespring.com/api/fast_post_order)
- Content Type: JSON (application/json)

:::hint{type="info"}
**license\_type** parameter is optional, use it to change the default license type if needed
:::



```java
{
  "company_uuid": "API_KEY_GOES_HERE",
  "id": "#{order.id}",
  "is_test": #{order.isTest},
  "created": "#{order.created}",
  "order_type": "#{order.type}",
  "customer_email": "#{order.customer.email}",
  "customer_reference": "#{order.customerReference}",
  "referrer": "#{order.referrer}",
  "license_type": "perpetual",
  "items": [ <repeat value="#{order.allItems}" var="orderItem">
     { 
     "product_name": "#{orderItem.productName}",
     "product_group": "#{orderItem.productGroup}",
     "price_total": "#{orderItem.priceTotal}",
     "license": {
        "key": "#{fulfillment.license.key}",
        "licenses": [<repeat value="#{orderItem.fulfillment.license.licenses}" var="value">"#{value}",</repeat>],
        "max_activations": 2,
        "product_features": ["standard"]
     }
  },</repeat>]
}
```

![Figure 8 - General Settings](https://kwiki-user-media.s3.amazonaws.com/content/image_widgets/classic_post_order.png "Figure 8 - General Settings")

Please do not hesitate to contact customer support if you need any help.

## Configuring Product Features

Product features in FastSpring can be set-up as "Product choices", which are actually **separate products** in FastSpring platform. This means that before setting up a feature/choice, you need to create a separate product. Take care to set product name in FastSpring to equal feature code in LicenseSpring. Also, place these products in a separate **product group** called "features".

Steps:

1. Define product feature(s) in LicenseSpring
2. Create a *product group* called **features** in your FastSpring store
3. Create "feature products" in "features" product group in your FastSpring store
4. Set up product choice on your base product in FastSpring by selecting "feature products" created in step 3

![Product Feature List](https://kwiki-user-media.s3.amazonaws.com/content/image_widgets/Screenshot_2019-04-05_at_15.07.07.png "Product Feature List")


[title] C++
[path] Frequently Asked Questions/SDK/

## VM Detection on the Windows platform when linking with the static libraries

VM detection is possible on Windows OS. linking to LicenseSpring library can be done statically or dynamically. LicenseSpring library loads LicenseSpringVMD.dll at run time, when detecting for VM. LicenseSpringVMD.dll cannot be used independently, only within LicenseSpring SDK.

## When using C++, there is a large number of files.Is it possible somehow to decrease the number of files to a small number?

To reduce the number of dynamic libraries your application requires, youcan statically link the libraries into your executable, incorporating their code directly into the application at compile time. This results  in a standalone executable that does not depend on external library files at runtime.

## What SSL certificates does the SDK use?

Check out the [**Extended options document**](https://docs.licensespring.com/sdks/tutorials/advanced-usage/extended-configuration#A4BVU) for more information about setting up native TLS for curl.

The C++ SDK uses multiple fallbacks to look up valid SSL certificates for reaching the License API. Certificates are checked in the following order:

- system certificates,
- SDK embedded certificates,
- certificates from a bundle file.

### Embedded certificates

The SDK contains a list of root certificates that are included in Mozilla products. See [**https://wiki.mozilla.org/CA/Included\_Certificates**](https://wiki.mozilla.org/CA/Included_Certificates).

### Certificate bundle file

The SDK also contains a standalone file containing the same certificates, that you can bundle with your binary.

On **Windows**, the SDK searches for `curl-ca-bundle.crt` and `ca-certificates.crt` files:

- with `SearchPath`, see [**https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-searchpatha**](https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-searchpatha),
- in the `certificates` folder, placed in the executable directory.

On **Linux and macOS**, the SDK searches for the `ca-certificates.crt` file:

- in the executable directory,
- in the `certificates` directory, placed in the executable directory,
- in the current working directory,
- in the `certificates` directory, placed in the current working directory.


If that fails, the SDK also tries to find a certificate file commonly found on different Linux and BSD distributions:

- /etc/ssl/certs/ca-certificates.crt
- /etc/pki/tls/certs/ca-bundle.txt
- /etc/pki/tls/cacert.pem
- etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
- /etc/ssl/cert.pem
- /usr/local/etc/ssl/cert.pem
- /usr/local/share/certs/ca-root-nss.crt
- /etc/openssl/certs/ca-certificates.crt
- /usr/local/etc/openssl/cert.pem

### How to identify which certificate was used to authenticate the License API?

This is currently not possible. Enabling logging will write `Failed to verify SSL certificate using system/embedded/ca file certs.` to the log file. If the request fails, an appropriate exception will be thrown.


[title] Overview & Installation
[path] Floating Server/Floating Server V2/

## What is the Floating Server V2?&#x20;

The Floating Server is LicenseSpring’s self-hosted licensing platform, providing the core features of the cloud platform locally. **Version 2&#x20;**&#x69;ntroduces improved setup, configuration, and management workflows to make deployment, provisioning, and administration easier. **This document** focuses on v2, detailing installation, configuration, and best practices for running the Floating Server in your environment.&#x20;

### **Key Highlights & Compatibility&#x20;**

| **Feature&#x20;**            | **Details**                                                                  |
| ---------------------------- | ---------------------------------------------------------------------------- |
| **Supported Platforms**      | Windows and Linux                                                            |
| **Supported SDKs (initial)** | C++, .NET, Java (more coming)                                                |
| **Database Support**         | SQLite (dev/test), PostgreSQL (prod)-**Production Recommendation**PostgreSQL |
| **Provisioning Options**     | Certificates or YubiKey tokens                                               |

## **Installation Options&#x20;**

**Option 1: Native Executable (Recommended)**

Download the appropriate binary:

- [**floating-server-linux-amd-2.2.0.zip**](https://s3.eu-central-1.amazonaws.com/floating-server/floating-server-linux-amd-2.2.0.zip)
- [**floating-server-windows-amd-2.2.0.zip**](https://s3.eu-central-1.amazonaws.com/floating-server/floating-server-windows-amd-2.2.0.zip)
- **Unzip and run directly, no Docker required.**

**Option 2: Docker Image&#x20;**

- Pull the image from Docker Hub.
- Run the container from the pulled image.

:::hint{type="info"}
The configuration file and provisioning steps ar&#x65;**&#x20;identical for both methods.** The only difference with Docker is that you **must mount the configuration&#x20;**&#x61;nd **provisioning files** so the container can access them.
:::

### Run Floating Server v2 with PostgreSQL and Docker

**Create a shared network**

:::BlockQuote
docker network create fsnet
:::

**Start PostgreSQL**

:::BlockQuote
docker run -d \\
&#x20; \--name fs-postgres \\
&#x20; \--network fsnet \\
&#x20; -e POSTGRES\_USER=fsuser \\
&#x20; -e POSTGRES\_PASSWORD=fspassword \\
&#x20; -e POSTGRES\_DB=fsdb \\
&#x20; -v pgdata:/var/lib/postgresql/data \\
&#x20; -p 5432:5432 \\
&#x20; postgres:16
:::

change the setting as needed.

**Modify Floating Server config file**

:::CodeblockTabs
yaml

```yaml
database:
  type: postgres
  host: fs-postgres
  port: 5432
  user: fsuser
  password: fspassword
  name: fsdb
  sslmode: "disable"
```
:::

**Pull the Floating Server v2 image**

:::BlockQuote
docker pull licensespring/floating-server-v2\:v2.2.0
:::

**Run Floating Server v2**

Mount the config file and the certs (certificates and private key generated in provisioning) folder from provisioning:

:::BlockQuote
docker run -d \\
&#x20; \--name fsv2 \\
&#x20; \--network fsnet \\
&#x20; -p 8080:8080 \\
&#x20; -v "$(pwd)/config:/app/config\:ro" \\
&#x20; -v "$(pwd)/certs\:/app/certs\:ro" \\
&#x20;licensespring/floating-server-v2\:v2.2.0
:::

In this sample, we have assumed the confing file is located in `./config` and certificates and private key in `./certs`.

**Verify**

- Floating Server API: `http://localhost:8080`
- Postgres: available at `fs-postgres:5432` inside the Docker network

**Docker Compose&#x20;**

The steps mentioned above are all inlucded in the following docker compose file. Place this file in the directory with folders `config` and `certs`, config containing `default.yaml` (config file) and certs containing all the certificates and private key generated in provisioning. and then run

```bash
docker compose up -d
```

Make any needed adjustments.

:::CodeblockTabs
docker-compose.yaml

```yaml
services:
  postgres:
    image: postgres:16
    container_name: fs-postgres
    environment:
      POSTGRES_USER: fsuser
      POSTGRES_PASSWORD: fspassword
      POSTGRES_DB: fsdb
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    networks:
      - fsnet
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-fsuser} -d ${POSTGRES_DB:-fsdb}"]
      interval: 5s
      timeout: 5s
      retries: 10
    restart: unless-stopped

  fsv2:
    image: licensespring/floating-server-v2:latest
    container_name: fsv2
    depends_on:
      postgres:
        condition: service_healthy
    ports:
      - "8080:8080"
    volumes:
      - ./config:/app/config:ro
      - ./certs:/app/certs:ro
    networks:
      - fsnet
    restart: unless-stopped

networks:
  fsnet:
    name: fsnet
    # If you've already created fsnet with `docker network create fsnet`,
    # uncomment the next line to reuse it instead of letting Compose create it:
    # external: true

volumes:
  pgdata:
```
:::

****

****

****

****

****

****

****

****

****

[title] PostgreSQL TLS
[path] Floating Server/Floating Server V2/

The Floating Server (FS) supports secure database connections over TLS. You can configure your PostgreSQL instance in two ways: :

- `sslmode=require`: Encrypts the connection (no hostname verification).
- `sslmode=verify-full`: ncrypts and verifies the server’s identity (recommended for production).

Depending on your use case, configure PostgreSQL with TLS((enable TLS, install cert/key) and then set the Floating Server connection accordingly:&#x20;

- **Encrypt-only:&#x20;**

:::BlockQuote
sslmode=require
:::

- **Full verification:&#xA0;**

:::BlockQuote
sslmode=verify-full
sslrootcert=/path/to/ca.pem
:::

## Setting up Verify-Full TLS for PostgreSQL **(single or multiple machine)**

### **1)**&#x43;reate a Certificate Authority (CA)&#x20;

This CA will be used to sign PostgreSQL server certificates. Clients will trust this **CA via&#x20;**&#x20;`sslrootcert`.

:::BlockQuote
mkdir -p \~/pg-tls && cd \~/pg-tls
:::

:::BlockQuote
\# Root CA (keep the key private)
openssl genrsa -out ca.key 4096
openssl req -x509 -new -key ca.key -sha256 -days 3650 \\
&#x20; -out ca.crt -subj "/CN=Org-Postgres-CA"
:::

**Artifacts:**

- **CA certificate** (for clients): \~/pg-tls/ca.crt
- **CA private key** (do not share): \~/pg-tls/ca.key

:::hint{type="info"}
If you already have an **organizational CA**, you may reuse it.
:::

### **2)**&#x49;ssue a Server Certificate for Each PostgreSQL Host&#x20;

Generate a server certificate for each PostgreSQL machine. The certificate must include the DNS name clients use to connect. If clients connect via IP, include the IP as a SAN as well.&#x20;

**Set your host values:**

:::BlockQuote
HOST="db1.example.com"  # the DNS name clients will use
IP1="1.0.1.1"    # if clients will connect by IP
:::

**Generate key + CSR config with SANs:**

:::BlockQuote
openssl genrsa -out server.key 4096
cat > server.cnf \<\<EOF
\[ req ]
distinguished\_name = dn
req\_extensions = v3\_req
prompt = no
\[ dn ]
CN = $\{HOST}
\[ v3\_req ]
extendedKeyUsage = serverAuth
subjectAltName = @alt
\[ alt ]
DNS.1 = $\{HOST}
$( \[ -n "$IP1"  ] && echo "IP.1  = $\{IP1}" )
EOF
:::

**Make it executable:&#x20;**

:::BlockQuote
openssl req -new -key server.key -out server.csr -config server.cnf
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial    -out server.crt -days 825 -sha256 -extfile server.cnf -extensions v3\_req
:::

**Artifacts for this host**

- Server leaf cert: `server.crt`
- Server private key: `server.key`

Repeat for each Postgres machine. Do not reuse the same private key across machines.

## **3)&#x20;**&#x49;nstall Certificates on the PostgreSQL Host&#x20;

:::BlockQuote
\# Copy leaf + key into the Postgres data dir
cp server.crt /PATH/TO/DATADIR/server.crt
cp server.key /PATH/TO/DATADIR/server.key
:::

:::BlockQuote
\# key must be restricted
chown postgres\:postgres /PATH/TO/DATADIR/server.\{crt,key}
chmod 600 /PATH/TO/DATADIR/server.key
chmod 644 /PATH/TO/DATADIR/server.crt
:::

### **Enable TLS + listen on your network**

1. **Find your Postgres data dir (**`$PGDATA`**):**

:::BlockQuote
sudo -u postgres psql -tAc "SHOW data\_directory;"
:::

1. **Open postgresql.conf and add/confirm these lines:**

:::BlockQuote
sudo -u postgres $\{EDITOR:-nano} "$PGDATA/postgresql.conf"
:::

:::BlockQuote
ssl = on
ssl\_cert\_file = 'server.crt'   # or an absolute path
ssl\_key\_file  = 'server.key'   # key must be chmod 600, owned by postgres
listen\_addresses = '\*'         # or a comma list like '10.0.1.15,127.0.0.1'
:::

### **Allow TLS connections from your client networks (order matters)**

1. **Open pg\_hba.conf:**

`sudo -u postgres ${EDITOR:-nano} "$PGDATA/pg_hba.conf"`

1. **Add these lines&#x20;*****near the top*****&#x20;(before broader rules) and adjust DB/user/CIDRs:**

:::BlockQuote
\# Tighten the CIDRs to your environment
hostssl  fsdb  fsuser  10.0.0.0/16     scram-sha-256
hostssl  fsdb  fsuser  192.168.0.0/24  scram-sha-256
:::

Restart Postgres (e.g., pg\_ctl -D /PATH/TO/DATADIR restart) and ensure port **5432** is open.

## **4) Client (Floating Server) connection using verify-full**

Clients must connect using the **same DNS name that’s in the server cert SAN**.

**Place the CA cert on the app host (or inside the container):**

- Example path: `/etc/ssl/certs/org-postgres-ca.crt`

**Config file:**

```yaml
database:
 type: "postgres"
 host: db1.example.com
 port: 5432
 user: fsuser
 password: fspassword
 name: fsdb
 sslmode: "verify-full"   # options: disable, require, verify-full
 sslrootcert: "/etc/ssl/certs/org-postgres-ca.crt"
```

## Run PostgreSQL with TLS in Docker

After you’ve created your certs (ca.crt, server.crt, server.key), mount them into the container and let an init script place them in Postgres’s data dir with the right ownership/permissions.

### 1) Init script (runs on first boot)

**Create&#x20;**`init/00-ssl.sh`:

```bash
#!/bin/bash
set -e
mkdir -p "$PGDATA/certs"
cp /certs/server.crt "$PGDATA/certs/server.crt"
cp /certs/server.key "$PGDATA/certs/server.key"
chown postgres:postgres "$PGDATA/certs/server."{crt,key}
chmod 600 "$PGDATA/certs/server.key"
chmod 644 "$PGDATA/certs/server.crt"

# Allow TLS clients (adjust DB/user/CIDRs!)
{
  echo "hostssl  fsdb  fsuser  10.0.0.0/16     scram-sha-256"
  echo "hostssl  fsdb  fsuser  192.168.0.0/24  scram-sha-256"
} >> "$PGDATA/pg_hba.conf"
```

**Make it executable:&#x20;**

```bash
chmod +x init/00-ssl.sh
```

### 2) Place Certificates&#x20;

Put your files in **./certs/:&#x20;**

:::BlockQuote
./certs/server.crt
./certs/server.key
:::

### 3) Start PostgreSQL Container&#x20;

```bash
docker run -d \
  --name fs-postgres \
  --network fsnet \
  -e POSTGRES_USER=fsuser \
  -e POSTGRES_PASSWORD=fspassword \
  -e POSTGRES_DB=fsdb \
  -v pgdata:/var/lib/postgresql/data \
  -v "$(pwd)/certs:/certs:ro" \
  -v "$(pwd)/init:/docker-entrypoint-initdb.d:ro" \
  -p 5432:5432 \
  postgres:16 \
  -c ssl=on \
  -c ssl_cert_file=$PGDATA/certs/server.crt \
  -c ssl_key_file=$PGDATA/certs/server.key \
  -c listen_addresses='*'
```

## Bash Script

The following script implements the steps described above. Create a file named **fs-pg.sh&#x20;**&#x61;nd copy the script into it. Make sure to adjust paths and parameters as needed.The` ca.crt` will be saved under `./pg-tls/.` This script only generates the certificates required for TLS setup.&#x20;

```bash
mkdir -p ~/pg-tls && cd ~/pg-tls
openssl genrsa -out ca.key 4096
openssl req -x509 -new -key ca.key -sha256 -days 3650  -out ca.crt -subj "/CN=Org-Postgres-CA"
HOST="localhost"
IP1="1.0.1.1"
openssl genrsa -out server.key 4096
cat > server.cnf <<EOF
[ req ]
distinguished_name = dn
req_extensions = v3_req
prompt = no
[ dn ]
CN = ${HOST}
[ v3_req ]
extendedKeyUsage = serverAuth
subjectAltName = @alt
[ alt ]
DNS.1 = ${HOST}
EOF

# Append SANs conditionally
[ -n "${IP1:-}" ] && echo "IP.1 = ${IP1}" >> server.cnf
openssl req -new -key server.key -out server.csr -config server.cnf
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial    -out server.crt -days 825 -sha256 -extfile server.cnf -extensions v3_req

# --- Install certs into Postgres and enable TLS ---

# 1) Discover PGDATA (works for macOS/Homebrew and Linux)
PGDATA="$(psql -tAc 'SHOW data_directory;' 2>/dev/null || sudo -u postgres psql -tAc 'SHOW data_directory;' || psql -d postgres -tAc 'SHOW data_directory;')"
PGDATA="$(echo "$PGDATA" | tr -d '[:space:]')"
[ -d "$PGDATA" ] || { echo "Could not determine PGDATA"; exit 1; }

# 2) Copy leaf + key into PGDATA (or PGDATA/certs if you prefer)
sudo cp server.crt "$PGDATA/server.crt"
sudo cp server.key "$PGDATA/server.key"

# 3) Set owner/group to match the data dir owner (works both on mac and Linux)
if command -v stat >/dev/null && uname | grep -qi darwin; then
  OWNER="$(stat -f %Su "$PGDATA")"
  GROUP="$(stat -f %Sg "$PGDATA")"
else
  OWNER="$(stat -c %U "$PGDATA")"
  GROUP="$(stat -c %G "$PGDATA")"
fi
sudo chown "$OWNER:$GROUP" "$PGDATA/server.crt" "$PGDATA/server.key"

# 4) Lock down permissions (Postgres requires 600 on the key)
sudo chmod 600 "$PGDATA/server.key"
sudo chmod 644 "$PGDATA/server.crt"

# 5) Enable TLS + listen in postgresql.conf
CONF="$PGDATA/postgresql.conf"
sudo sed -i.bak -e "s/^#\?ssl *=.*/ssl = on/" \
                -e "s/^#\?ssl_cert_file *=.*/ssl_cert_file = 'server.crt'/" \
                -e "s/^#\?ssl_key_file *=.*/ssl_key_file  = 'server.key'/" \
                -e "s/^#\?listen_addresses *=.*/listen_addresses = '*'/" "$CONF" \
  || {
    # Fallback: append if keys not present
    sudo tee -a "$CONF" >/dev/null <<'EOS'
ssl = on
ssl_cert_file = 'server.crt'
ssl_key_file  = 'server.key'
listen_addresses = '*'
EOS
  }

# 6) Allow TLS clients from your networks (add hostssl lines if missing)
HBA="$PGDATA/pg_hba.conf"
add_hba() { grep -qF "$1" "$HBA" || echo "$1" | sudo tee -a "$HBA" >/dev/null; }
add_hba "hostssl  fsdb  fsuser  all     scram-sha-256"

# 7) Reload or restart Postgres
# Try a reload first:
psql -tAc "SELECT pg_reload_conf();" 2>/dev/null \
  || sudo -u postgres psql -tAc "SELECT pg_reload_conf();" 2>/dev/null \
  || {
    # If reload isn't available, do a restart 
    if command -v brew >/dev/null; then
      # macOS Homebrew service name may vary (postgresql@16, etc.)
      brew services restart postgresql || true
else
      sudo systemctl restart postgresql 2>/dev/null || \
      sudo service postgresql restart 2>/dev/null || \
      sudo -u "$OWNER" pg_ctl -D "$PGDATA" restart
    fi
  }
```

## Notes

- The init script runs **only when the&#x20;**`pgdata`**&#x20;volume is new/empty**. If you’ve already used it, either remove the volume and re-run, or copy the files into $PGDATA/certs and fix ownership/permissions manually.
- Adjust DB/user/CIDRs to your environment.
- On the Floating Server side, use `sslmode=verify-full` and point to your CA: `sslrootcert=/path/to/ca.crt`.
- **Paths and exact details** may vary in your environment (OS, image, mount points). Adjust them as needed. The only requirements are that Postgres can read the certs at the paths you configure and that `server.key` is owned by postgres with `0600` permissions.


[title] SalesForce Integration User Documentation
[path] Integrations/Salesforce/

## Introduction

The following article will take you through our Salesforce integration and all its current functionalities.

The current integration supports "**Account"** and "**Contact"** **SalesForce** **objects**, and the integration is able to be set up on **Record Lightning pages.**

## Prerequisites

We assume that you have a **Salesforce** and a **LicenseSpring** instance setup beforehand.

We assume that you have already gone through the **Salesforce Integration Setup&#x20;**&#x64;ocument and have intalled and setup the integration application in your SalesForce instance.

We assume that you have the necessary **rights** in your Salesforce instance to use the installed integration.

## Contacts

If you have installed the app correctly and added the **management api key** + added it to your **contact record page**, you will be able to see the following window once you open up a contact (any contact) that you have in you SaleForce instance.

:::hint{type="info"}
Depending on your Lightning record page setup, you might have slightly different options or UI available.
:::

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/d-kgwNnFX8RMX_0LHlL6K_screenshot-2024-10-31-at-140835.png)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/IAplWC3UtOtMGYEW6l5sE_screenshot-2024-10-31-at-140919.png)

### Connecting Contacts to LicenseSpring Customers

Initially the contact is not automatically connected to the co-responding customer in LicenseSpring (image below). Once you create a license on the contact, then all the periously created licenses for that contact will also show up in our integration, and moving forward you'll always see all the licenses on that co-responding contact.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/q-FEuCPZ8pv8FVprcYJJc_screenshot-2025-04-22-at-150917.png)

:::hint{type="info"}
The integration will look for the LicenseSpring customer with the same mail, and if it does not find one in your LicenseSpring instance, it will create a new cutomser in LicenseSpring with the data from the SalesForce contact on which you tried to create the license
:::

If you want to connect the contact to an already exiting LicenseSpring customer, but you have multiple customers with the same email and you want to pick which one to conenct to, you can do so by clicking on the "Settings" button in the top right corner of the integration window. This will open up a drop down and in it you need to select the "Connect Customer" option. This will open up the following window in the image below.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/sokxlsYby11vePZ3-D3hG_screenshot-2025-04-22-at-151059.png)

In this pop up window, in the drop down you need to select which customer to connect to from LicenseSpring. The drop down will only show you the customers that have the same name as your contact in SalesForce. Once you pick which customer you just need to click on the "Connect" button and that is it.

:::hint{type="danger"}
Customer data in LicenseSpring will be overwritten with data from the Salesforce contact
:::

### Creating Licenses

If we click on the "**Create Licenses**" button in the top right corner of the integration window, we will see the following screen.

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/n2TmWDeO7k4cps7kwuVgu_screenshot-2024-10-31-at-141121.png" signedSrc size="88" width="1890" height="496" position="center" caption darkWidth="1890" darkHeight="496"}

On this screen we are able to pick a **product** from our connected **LicenseSpring** instance.

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/7pToCdwZoHvzeFSadNt4R_screenshot-2024-10-31-at-141432.png" signedSrc size="84" width="946" height="180" position="center" caption darkWidth="946" darkHeight="180"}

Once we select a **Product**, we will be able to pick a **License** **Policy**, and depening on the picked **License Policy** type we will see aditional settings below the drop down.

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/kTThtE_Yg1eeDc7J_57lt_screenshot-2024-10-31-at-141720.png" signedSrc size="82" width="949" height="413" position="center" caption darkWidth="949" darkHeight="413"}

In this case we sleected a subscription type policy and we are shown two additional fields for the **Quantity** of the licenses and the **Validiy** **Period** of the **licenses&#x20;**&#x74;hat we plan to create.

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/AJijxY66iEJYDLvZhjfEh_screenshot-2024-10-31-at-142413.png" signedSrc size="84" width="942" height="410" position="center" caption darkWidth="942" darkHeight="410"}

Once we have selected a **LicensePolicy** (in this case a **subscription** LicensePolicy) on the left side of the app we can see additonal information about that **LicensePolicy.**

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/IzyIq8n-6VYk6d2HPlZfI_screenshot-2024-10-31-at-142516.png" signedSrc size="84" width="937" height="420" position="center" caption darkWidth="937" darkHeight="420"}

If we have all our settings picked out, we can click on the "**Create Order**" button and after a small loading period (depending on the quantity of the licenses), we can see all of our licenses that got created.

:::hint{type="info"}
If the contact with which you have created your licenses does not exist in your LicenseSpring instace, it will be created there once you clikc on the "**Create Order**" button.
:::

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/7_U-xpdaKfnR0CfPrMro4_screenshot-2024-10-31-at-150802.png)

### Updating Licenses

Once the **contact** has its **licenses** created, you have the ability to update some **license** **parameters** (depending on the license type you created).

If we click on the little **arrow dropdown** on the right side of the license row, and then click on the **update** **button**, we are show all the fields that we can update.&#x20;

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/AzsjuQB5mbweqBvC57T51_screenshot-2024-10-31-at-150956.png)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/pdhAG0lbe8nI_Zs5B6MUh_screenshot-2024-12-12-at-150934.png)

### Product Features

If the product that your license is connected to has Product features, you will be able to add or remove them when your're updating your license.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/jkaCCjweCTmlupI9ZiVaX_screenshot-2024-12-12-at-151305.png)

To do so you can click on the "Add features" button in the lower right corner of the window which will open a section on which you can by clicking/selecting the feature you like and using the arrows in the middle of the screen add additional product features to the license

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Oaeu3Se0RHMmkYpfGYWm5_screenshot-2024-12-12-at-152128.png)

Once you're done you need to click on the "Add features" button, and this will add the product feature to the respective license

### Custom Fields

When updating your licenses, in the update window there is a section for custom fields.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/qIQbRq4aHtWEaEfU_WpLl_screenshot-2024-12-13-at-141426.png)

You are able to edit the custom fields value by clicking on the "edit" button next to the custom field that you wish to edit.&#x20;

This will open up an another pup up window on which once you're happy with your edit, you can click on the  "Update custom field" button to save the changes

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8u4GTMC9rn6faWH7tVBel_screenshot-2024-12-13-at-142254.png)

## Accounts

On our accounts objects the integration window will show all the the licenses that are connected to any contacts that are associated with the account that we opened up.

So for example if we have two **contacts**, one called "Andy Young" and the other "Arthur Song" that are connected to the **account** called "Main Bank".

Arthurs account has 5 perpetual licenses on it and Andys has a bunch of subscription licenses on his account.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/VvcxKuGTOX9zdDpSLNj3M_screenshot-2024-11-04-at-160758.png)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/5VShXrW1MBt6MHVcXlxxT_screenshot-2024-11-04-at-161340.png)

So the Main Bank account will show on its record page all of the licenses together, as mentioned above.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8tMQS5LcewQOISbG4xZPy_screenshot-2024-11-11-at-145310.png)

### Connecting Account to LicenseSpring Account Groups

The same proccess can be followed as mention above on the "Connecting Contacts to LicenseSpring Customers" which is:

1. Click on the "Settings" button in the top right corner of the integration window
2. In the new pop up window select which LicenseSpring account you want to connect to
3. Click on the "Connect" button

:::hint{type="danger"}
Account data in LicenseSpring will be overwritten with data from Salesforce accounts
:::

### Creating Licenses Though Accounts

Same as we have it with **Contacts, Accounts&#x20;**&#x61;lso have a button to create licenses with. The only difference is that you can if you want to pick a Contact that is associated with that account that can be the holder of the licenses instead of the account.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/MdqSOBDrnpLSam-TXhHcu_screenshot-2024-11-11-at-144732.png)

All the other options are the exact same, where you need to pick a product and so on.

### Update Licenses Through Accounts

If you want to update licenses, you can click on the customers email, which will redirect you to the Contact record page on which you will be able to update the contact as detailed above in this document.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/B0Ggqbi_-D-KG-2m5RMrf_screenshot-2024-11-11-at-145451.png)

### Select a Field for the Account Short Code

If you want the short code to be generated from a value other than the Account name, open **LicenseSpring Settings** and select a different unique Account field.

In Salesforce, click the **App Launcher** (the nine dots in the upper-left corner), then search for **"LicenseSpring Settings"**. Select it to open the settings screen. From there, the user can choose which unique Account field will be used to determine the Account short code in LicenseSpring.

![](https://archbee-image-uploads.s3.amazonaws.com/iXqw_Qyw6yXxFXCWKyPYs-xErOyFT5nzfw0r-QehSTW-20250816-105733.png)

## Automations

If you want licenses to be automatically created after an object (Lead, Contact, or Account) is created, you can configure the automation in the **LicenseSpring Settings** screen. There, you can select which object the automation applies to and specify the product and license policy to be used in the automation

![](https://archbee-image-uploads.s3.amazonaws.com/iXqw_Qyw6yXxFXCWKyPYs-etav5JrRgHnxshQq4gDDH-20250829-101113.png)

![](https://archbee-image-uploads.s3.amazonaws.com/iXqw_Qyw6yXxFXCWKyPYs--MP88PFe5OCk3DJop0LsR-20250829-101136.png)

:::hint{type="warning"}
Certain objects require specific fields to be initialized with unique values. For example, Contacts and Leads must have an email address defined, while Accounts require a short code. The short code is generated based on the Account name, or from another field if the user has selected one, as shown [**here**](https://app.archbee.com/docs/FbT_Z5Cu33D-LVZx1fRkU/7IEN7ksl1O5Uzvlzhi9DV#VLTo_)
:::

### Logs

If for some reason you do not see the license that was sopposed to be created by the automation, please take a loot at the logs that the integration provided.

To do so you will need to go to the "App Launcher" and seach for the "Integration Logs"

::Image[]{src="https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/sHvG7i0CGVuGtYpiHfJ-A_screenshot-2025-09-05-at-144805.png" signedSrc size="60" width="357" height="307" position="center" caption darkWidth="357" darkHeight="307"}

Do not forget to switch the fileter in the logs table to "All" to see all the available logs.

::Image[]{src="https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/lcdzpr8xInNOMX-Vb5QFU_screenshot-2025-09-05-at-144814.png" signedSrc size="60" width="731" height="320" position="center" caption darkWidth="731" darkHeight="320"}

If you need help after looking at the logs, please contact out support team and they will assist you as soon as possible [**https://licensespring.zendesk.com/hc/en-us/requests/new**](https://licensespring.zendesk.com/hc/en-us/requests/new)

## Additional Features and Support Requests

If you have use cases where you wish that aditional SalesForce objects are supported in our integration or additional LicenseSpring features are available in the integration inside Salesforce, let us know by contacting our dev team  [**https://licensespring.zendesk.com/hc/en-us/requests/new**](https://licensespring.zendesk.com/hc/en-us/requests/new)

If for some reason the integration is not behaving as it is documented here, let us know by contacing our support team: [**https://licensespring.zendesk.com/hc/en-us/requests/new**](https://licensespring.zendesk.com/hc/en-us/requests/new)

[title] consumption
[path] Floating Server/Floating Server V1/API Reference/


[title] Add consumption
[path] Floating Server/Floating Server V1/API Reference/consumption/

{
  "id": "nYXjTOcvo--O70qnVuXF7",
  "data": {
    "url": "http://localhost:8080/api/v4/add_consumption",
    "name": "Add consumption",
    "method": "POST",
    "request": {
      "pathParameters": [],
      "queryParameters": [],
      "headerParameters": [],
      "bodyDataParameters": [
        {
          "kind": "optional",
          "name": "body",
          "type": "object",
          "schema": [
            {
              "kind": "optional",
              "name": "product",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "consumptions",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "max_overages",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "allow_overages",
              "type": "string",
              "example": ""
            }
          ],
          "isExpanded": true
        }
      ],
      "formDataParameters": []
    },
    "responses": [
      {
        "statusCode": "200",
        "description": "",
        "jsonExample": ""
      }
    ],
    "contentType": "application/json"
  },
  "type": "api-oas-v2",
  "children": [
    {
      "text": ""
    }
  ]
}
[title] Frequently Asked Questions
[path] Common Scenarios/Single Sign On (SSO)/

### **Is there a way for Customer Account SSO to auto-create a LicenseSpring user on login?**

Not at the moment. Automatic user creation is **only available for platform users**.

### **What does "Implemented Keycloak integration in all API endpoints" in v4.0.35 mean?**

The IdP system has changed, and all SSO setups have been migrated. If you see unexpected behavior, such as different authentication types being displayed (e.g., OIDC vs. SAML), please send the specific setups to support for verification.

### Is auth URL for identity providers the same on single tenancy accounts?

No, for single tenancy accounts, auth url is provided by us instead of default one ( `auth.licensespring.com` ). This auth URL is used when registering your application in identity providers dashboard.


[title] Stripe
[path] Integrations/

![Stripe Logo](https://kwiki-user-media.s3.amazonaws.com/staging/content/image_widgets/stripe-logo_ZMC1ZmF.png "Stripe Logo")

LicenseSpring supports creating orders and maintaining subscriptions through our custom Stripe integration solution. Stripe serves as a single source of truth where both customer and order details received from Stripe webhook events are used to create orders and licenses and renew or cancel subscriptions in LicenseSpring platform.

Steps needed to implement Stripe integration to your own LicenseSpring platform account are described in the next page. For any questions please contact our customer support.

**Additional Resources:**

[**Stripe Documentation**](https://stripe.com/docs)

[**Stripe API Documentation**](https://stripe.com/docs/api)



[title] Changelog
[path] /


[title] User Interface (UI) Overview
[path] Floating Server/Floating Server V2/

The **Floating Server UI** allows you to manage licenses efficiently. You can:

- **Activate&#x20;**&#x61;nd **deactivate&#x20;**&#x6C;icenses (online, offline, air‑gapped)
- **Trigger synchronizations** with the License API
- **Update** server configuration
- **Review** users registered to licenses and features

## Licenses Page

The **Licenses page** lists all licenses added to the server.

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/5uzjDMRaA9rIei0eL1Zpr_image.png "License Page on Floating Server")

### Key Actions

- **Add a license**: Enter a license key or upload a license file.
- To add a bundle license to a floating server:

:::hint{type="info"}
Ensure the **License Type&#x20;**&#x69;s set to **Bundle**. (See picture below)
:::

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/pEUMIn-YyoqZFo9cpIBX__image.png "Adding Bundle License")

To add a bundle license to a floating server, ensure that your bundle License Policy is configured for floating licenses. Specifically, set  Offline Floating License = Yes to enable the license to function as a floating license on the server.(See picture below)

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/24l5n7e1e6tR_G8FjSNSs_image.png "Bundle License Policy Set as Floating License")

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/173RP58Mhslg2dKTKB6ce_image.png "Bundle License View in FS")

:::hint{type="info"}
With the release of **Floating Server**[**&#x20;v2.1.0,**](https://docs.licensespring.com/Floating-server-v2/overview-and-installation#RBuN1) product **features are now fully visible for both individual Floating Licenses and Bundle Licenses**.
:::

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/zRhNjSzTWH5Eff8bXlEIY_image.png "Bundle Features")

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/fKQ8tn7llhkdInmeNFTYn_image.png "License Features")

- **Activate / Deactivate licenses**:
  - **Online:** Uses the License API directly
  - **Offline / Air‑gapped:** See Offline & Air‑gapped Licensing below
- **View details**: Inspect license status, expiry, features, and usage
- **See registered users**: Click on a license to view users associated with that license and its features

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/xoGpHrAqFni9nDmCkF5-t_image.png "License's Detail Page")

- **Trigger a sync**: Push local consumption data and pull updates (button located at the top right)

## Offline & Air‑gapped Licensing

Use this page when the server **cannot reach the License API directly**.

- Supports generating and uploading activation/deactivation files or codes for offline and air‑gapped environments
- Starting from V2.1.0, this page supports the refreshing of offline licenses and bundles.
- Refer to the respective endpoints for detailed workflows

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/A8FL_fuXMX-iwJU8MGxGC_image.png)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Z89qR_b75PQ2EJnDddSor_image.png)

## Offline Refresh

:::hint{type="info"}
This offline update functionality was introduced in **v2.1.0**.
:::

To update a license or bundle that has been added to the Floating Server using the offline method:

1. Navigate to the license’s page on the platform.&#x20;
2. Locate the **refresh file** under the **Devices** section.&#x20;

![](https://app.archbee.com/api/optimize/IJdHyjBlO9LOXOrDnWJTx/WMig2Yd5Neul0j48pvlPv_image.png "Download License Refresh File")

Upload this file using the corresponding form on the Floating Server.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ezTb9LTiguhtnJrs2HPaB_image.png)

## Configuration Page

Adjust server-level settings that affect synchronization, connectivity, and other global options.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ofxZHod0OEo3Z0DBJtV5v_image.png)

### Periodic Synchronization

The server automatically synchronizes with the License API to maintain a consistent state.

**During synchronization:**

- Sends local consumption data to the License API
- Pulls license updates, including status, features, expiration dates, and usage limits

**How to configure synchronization:**

- Set the **Sync period** on the Configuration page
- Use **Sync Data** (top-right) to trigger a manual synchronization at any time

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/vbhu6ZPU79QRr2xUyvzmQ_image.png)

## Using the Swagger Page

The Swagger interface allows you to test API endpoints directly.

**Example: Adding a license**

1. Fill out the required fields in the request body
2. Click **Execute**
3. If successful, the server will return the appropriate response

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/_veeII29UK10iExyttJwf_image.png)

**Authorization:**

- Look for the small lock icon 🔒 (or authorization icon) on the right side of the endpoint
- Click it and provide your JWT token in the format:

:::BlockQuote
Bearer \<your-jwt-token>
:::

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/G_SY9Vcju-WW2Q5DD0Usw_image.png)

## Using CLI Instead of Swagger

After testing an endpoint in Swagger, you can switch to the **command line interface (CLI)**:

- Copy the equivalent **curl command** generated by Swagger (visible below the response section)
- Paste it into your terminal to execute the same request

**

[title] Postman Collections
[path] Common Scenarios/Glossary/

## Management API Collection

The **Management API Postman Collection** provides a complete and structured set of requests for interacting with the LicenseSpring Management API.
&#x20;It enables developers to manage customers, products, licenses, devices, accounts, features, labels, analytics, and other platform resources.

The collection is fully integrated with the shared environment file, allowing automatic population of resource IDs for fast and efficient testing.

::File[]{src="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/eLnT3arvPiFM4ZejYJMnI-20251028-120459.json" signedSrc="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/eLnT3arvPiFM4ZejYJMnI-20251028-120459.json" label="LicenseSpring Management API.postman_collection.json"}

## License API Collection

The **License API Postman Collection** is a valuable resource designed to empower businesses in efficiently managing their software licenses, it includes all essential endpoints for working with software licensing.

This collection supports **API Key** and **Shared Key** authentication and uses environment variables for product codes, license keys, and hardware IDs, making setup quick and flexible.

::File[]{src="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/infInPmhjmIMhBmP9bIFg-20251028-120550.json" signedSrc="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/infInPmhjmIMhBmP9bIFg-20251028-120550.json" label="License API.postman_collection.json"}

The **License API – OAuth Postman Collection** provides the same licensing functionality as the standard License API collection, but using **OAuth authentication**.

The collection includes:

- Token generation flow using client\_id and client\_secret&#x20;
- Automatic insertion of access tokens into all subsequent requests&#x20;
- Fully aligned endpoints with the non-OAuth License API&#x20;

This makes it suitable for secure server-side integrations and enterprise setups where OAuth is required.

::File[]{src="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/qLdYvI7_1LG4tt7dgU5qa-20251106-094945.json" signedSrc="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/qLdYvI7_1LG4tt7dgU5qa-20251106-094945.json" label="License API - Oauth.postman_collection.json"}

## User Environment Collection

The LS Environment Postman Collection is a valuable asset aimed at streamlining the management of user environments.&#x20;

This collection provides a curated set of API requests and endpoints, simplifying the interaction with user environment configurations.

::File[]{src="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/3ewFHvZgTI4KIje6E4Po5-20251028-120712.json" signedSrc="https://archbee-doc-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/3ewFHvZgTI4KIje6E4Po5-20251028-120712.json" label="LS Environment.postman_environment.json"}

# **How to Import and Use**

1. Open Postman&#x20;
2. Go to **Environments → Import** → select LS Environment.json&#x20;
3. Go to **Collections → Import** and import:&#x20;
   - License API.postman\_collection.json&#x20;
   - License API – OAuth.postman\_collection.json&#x20;
   - LicenseSpring Management API.postman\_collection.json&#x20;
4. Select the **LS Environment** from Postman’s environment dropdown&#x20;
5. Run List requests to populate variables&#x20;
6. Use the collections normally — all requests will use environment variables dynamically

# **Notes**

- The setup is fully customizable; users may modify or extend variables and requests.&#x20;
- All required variables for License and Management APIs are available through the LicenseSpring platform UI.&#x20;
- Management API POST requests include example payloads based on official API documentation.&#x20;
- License API requests depend on: *apiKey and sharedKey&#x20;*&#x6F;r if using Oaut&#x68;*&#x20;client\_id and client\_secret&#x20;*&#x61;nd requests mostly requir&#x65;*: default\_product\_code,default\_license\_key and default\_hardware\_id.*
  &#x20;Once set, *headers and bodies are generated automatically*.&#x20;
- Environment values must not contain trailing spaces or hidden characters.
  &#x20;Such issues commonly cause URL errors, authentication failures (401), or unexpected 400/404 responses.&#x20;
- OAuth-specific folders in the **Management API** require populated IDs (e.g., license\_id, customer\_id).
  &#x20;These are filled automatically when List requests are run, or they can be set manually.

[title] Java
[path] Frequently Asked Questions/SDK/

## What is the relationship of an Offline licensing instance and the gracePeriodDays & ignoreServerExceptions parameters? How and when do these parameters interact with an Offline licensing instance?

The behavior depends on how the offline mode is configured:

### Offline Mode Enabled

- No online license checks are made.
- `gracePeriodDays` and `ignoreServerExceptions` are ignored.
- License validity is checked locally using cryptographic signatures.

### Offline License Used in Online Mode

- `checkLicense()` calls will still be made.
- `gracePeriodDays` allows server exceptions to be ignored for a limited time.
- If `ignoreServerExceptions` is set to true, server-related exceptions will be ignored indefinitely, and the local license will be used instead.


[title] Platform changelog
[path] Changelog/

### February 10, 2026, v3.245.0

- Bulk deletion of Licenses skips air gapped Licenses
- Fixed airgap license policies selection bug on order creation
- Expanded Company Feature flags checking

### February 4, 2026, v3.244.0

- Floating Feature borrow and release functionality

### January 19, 2026, v3.243.0

- Added HubSpot Account ID on Hubspot integration setup
- Implemented Custom Fields UX Enhancements
  - Implemented UI distinction between License and Product Custom Fields
  - Implemented reseting license custom fields to product custom field value
  - Refined logic for allowed values on custom fields, the default value is now always present in the allowed values
  - Implemented reseting all license custom fields for a product
  - Added explanatory labels for setting license custom fields and overriding product default custom fields
- Fixed Hubspot and Fastspring integration documentation URL's updated to point to the correct documentation page
- Billing warning banner logic changed for unpaid invoices/subscriptions
- Default number of Platform Users for Business Starter plan has been updated to 3

### January 16, 2026, v3.242.0

- Fixed Features tab not showing on order creation
- Reworked billing system
- Added License type validation on Licenses CSV import

### January 12, 2026, v3.241.0

- Customer Account SSO accepts now multiple redirect URI's instead of one
- Management API: Removed `cognito_user_pool_id`, `keycloak_redirect_uri` from Customer Account object(s)

:::Changelog{title="v3.240.0 (16.12.2025.)"}
::ChangelogItem{type="fixed" description="Refactored app startup logic and token refresh handling to improve reliability and user experience"}

::ChangelogItem{type="added" description="New license manager permissions for editing customers, editing licenses, editing license custom fields, editing license product features"}
:::

:::Changelog{title="v3.239.0 (04.12.2025.)"}
::ChangelogItem{type="added" description="Support for OIDC identity provider when setting up SSO on company settings page and customer account SSO tab"}

::ChangelogItem{type="added" description="Licenses search filter: search by license ID"}

::ChangelogItem{type="fixed" description="Prevent duplication of Company Members in rare cases with unique constraint"}

::ChangelogItem{type="added" description="Management API: Support for setting metadata per manager when adding managers in bulk to Order"}
:::

:::Changelog{title="v3.238.0 (27.11.2025.)"}
::ChangelogItem{type="fixed" description="Improved customer display in dropdown when adding customers to accounts - now shows email, full name with ID, company name, or ID as fallback in priority order"}

::ChangelogItem{type="fixed" description="Device list sorting now properly handles unsupported sort fields"}

::ChangelogItem{type="fixed" description="Licenses with extremely high number of Devices not loading"}
:::

:::Changelog{title="v3.237.0 (20.11.2025.)"}
::ChangelogItem{type="fixed" description="Validation for `code` on Product Feature Groups"}

::ChangelogItem{type="added" description="Validation for `default_value` on Product Custom Fields and License Custom Field Templates"}

::ChangelogItem{type="fixed" description="Properly handle exceptions on setting License User passswords"}
:::

:::Changelog{title="v3.236.2 (04.11.2025.)"}
::ChangelogItem{type="added" description="Global Features"}

::ChangelogItem{type="added" description="Patch request wrapper for license, license-templates and product endpoint that filters out only the difference between the old object and the updated object."}

::ChangelogItem{type="added" description="Validation logic in the patch wrapper for license endpoint"}

::ChangelogItem{type="added" description="Metadata filtering for All Pages, updated UI for standard filters"}

::ChangelogItem{type="added" description="Disabled/enabled input fields for included/excluded features (trial, maintenance period) on license edit, license create, license policy edit"}

::ChangelogItem{type="fixed" description="Issue with custom fields allowed values to preload on license creation and license policy update as dropdown"}

::ChangelogItem{type="fixed" description="Issue with refreshing token and redirecting to home page (now preserves current page)"}

::ChangelogItem{type="fixed" description="Issue with not displaying license user/key on order page -> licenses tab of bundle licenses"}

::ChangelogItem{type="added" description="Management API: `product__isnull`, `product_or_null` filters on listing Product Features"}

::ChangelogItem{type="added" description="New logic for validating Product Feature code uniqueness to include Global Features"}

::ChangelogItem{type="added" description="New logic for validating Product Feature Group code uniqueness to include Global Feature Groups"}

::ChangelogItem{type="fixed" description="Customer Label related filters"}
:::

:::Changelog{title="v3.235.0 (21.10.2025.)"}
::ChangelogItem{type="added" description="HubSpot activation and deactivation buttons on integrations page (buttons are back)"}

::ChangelogItem{type="added" description="Added Last login block field with information on License User details page"}

::ChangelogItem{type="fixed" description="Pasting functionality for Custom Fields (Allowed values)"}

::ChangelogItem{type="fixed" description="Adding `Google` and `Apple` SSO identity providers on Company level"}

::ChangelogItem{type="added" description="Management API: Deleting Orders"}

::ChangelogItem{type="added" description="`product_name__icontains`, `short_code__icontains`, `authorization_method`, `active` and `allow_trial` filters on listing Products"}
:::

:::Changelog{title="v3.234.0 (14.10.2025.)"}
::ChangelogItem{type="added" description="If custom fields have allowed values, show a dropdown instead of a text input"}

::ChangelogItem{type="added" description="`license.checked`, `license.released` webhook events"}

::ChangelogItem{type="added" description="`License will expire` email notifications for license managers"}

::ChangelogItem{type="added" description="`active` filter on `/api/v1/licenses/` endpoint"}

::ChangelogItem{type="fixed" description="Allow default value from Product Custom Field with `value` enumerations to be set on License Custom Field"}

::ChangelogItem{type="fixed" description="Deletion of License Users migrated to Keycloak"}

::ChangelogItem{type="fixed" description="Populating metadata on License Manager creation"}

::ChangelogItem{type="added" description="`short_code` in Product objects in License objects on retrieving Order"}
:::

:::Changelog{title="v3.233.0 (25.09.2025.)"}
::ChangelogItem{type="added" description="Floating server documentation URL updated to v2 version"}

::ChangelogItem{type="added" description="Schema version selector for offline request settings - users can now choose between different schema versions for offline requests"}

::ChangelogItem{type="added" description="Configuration form for floating server settings with comprehensive configuration options including:&#xA;    - PostgreSQL SSL configuration options with validation&#xA;    - cloud configuration fields with improved grid layout&#xA;    - verbose logging option with descriptive tooltip&#xA;    - customizable OAuth client handling"}

::ChangelogItem{type="added" description="Automatic YAML config file download after saving floating server configuration (downloads as `default.yaml`)"}

::ChangelogItem{type="added" description="`Download certificate chain` button to floating server details page"}

::ChangelogItem{type="fixed" description="Removed HubSpot activation and deactivation buttons from integrations page (done from HubSpot now)"}

::ChangelogItem{type="fixed" description="Mangement API: Listing License Users returns `metadata` field for each License User"}
:::

:::Changelog{title="v3.232.0 (15.09.2025.)"}
::ChangelogItem{type="fixed" description="Fixed crash when no airgap license policies defined and user selects Set as air-gapped"}

::ChangelogItem{type="fixed" description="Disable time-limited settings when trial is enabled and show info notice (time limited licenses)"}

::ChangelogItem{type="fixed" description="Audit logs initial double request issue"}

::ChangelogItem{type="fixed" description="Properly remove expiry from feature when checkbox is unchecked"}

::ChangelogItem{type="fixed" description="Set default maintenance duration type to period (date) instead of duration (days)"}

::ChangelogItem{type="fixed" description="Update floating server v2 documentation link"}
:::

:::Changelog{title="v3.231.0 (29.08.2025.)"}
::ChangelogItem{type="added" description="Remove public key display from floating server details"}

::ChangelogItem{type="fixed" description="Prevent race conditions in max activations validation and update error messages"}

::ChangelogItem{type="fixed" description="Validation of expiry date and duration fields when expiration is enabled"}

::ChangelogItem{type="added" description="Standardize modal title to &#x22;Add User to User Group&#x22; across all components doing that task"}

::ChangelogItem{type="added" description="Management API: `append_product` optional param on `/api/v1/orders/generate_license/` endpoint"}
:::

:::Changelog{title="v3.230.1 (22.08.2025.)"}
::ChangelogItem{type="fixed" description="Issue with loading devices on devices tab"}

::ChangelogItem{type="fixed" description="Duplication of email notifications in some cases for expiration notification policies"}
:::

:::Changelog{title="v3.230.0 (13.08.2025.)"}
::ChangelogItem{type="added" description="Management API: `order__customer_account__name`, `order__customer_account__name__icontains`, `order__customer_account__code`, `order__customer_account__code__icontains` filters on listing Licenses"}

::ChangelogItem{type="fixed" description="Product name display in licenses table on orders page"}
:::

:::Changelog{title="v3.229.0 (01.08.2025.)"}
::ChangelogItem{type="added" description="Floating server provisioning page"}

::ChangelogItem{type="fixed" description="Devices list now uses license id instead of license query param"}

::ChangelogItem{type="added" description="`allow_offline_activation` field to Licenses CSV imports and exports"}
:::

:::Changelog{title="v3.228.0 (15.07.2025.)"}
::ChangelogItem{type="added" description="`expiry_date` and `valid_duration` fields to Product Feature Users"}

::ChangelogItem{type="added" description="`valid_duration` field to License Product Feature"}

::ChangelogItem{type="added" description=" `product_feature_groups__id` filter on listing Product Features"}

::ChangelogItem{type="added" description="Endpoints for working with Product Feature Groups"}

::ChangelogItem{type="fixed" description="Total activations on License for a License User are updated on Device reset"}

::ChangelogItem{type="added" description="Unlock button for locked license users"}

::ChangelogItem{type="added" description="Activation type on device details"}

::ChangelogItem{type="added" description="Allow offline activation toggle on a license and license policy"}

::ChangelogItem{type="added" description="Removed legacy Salesforce integration activation flow"}
:::

:::Changelog{title="v3.227.0 (01.07.2025.)"}
::ChangelogItem{type="added" description="Management API: `managing_customer_accounts__isnull`, `license__order__customer_account` filter on listing License Users"}

::ChangelogItem{type="added" description="Management API: `total_licenses` field in License User objects on listing and retrieving License Users"}

::ChangelogItem{type="added" description="Management API: `customer_accounts` field (list of Customer Account objects containing `id` and `name`) in License User object when retrieving License Users"}

::ChangelogItem{type="added" description="Management API: `product__authorization_method` filter on listing Licenses"}

::ChangelogItem{type="added" description="Management API: Endpoints for working with license managers on Customer Accounts and License User Groups"}

::ChangelogItem{type="added" description="`license_user_group_created`, `license_user_group_updated`, `license_user_group_deleted`, `license_user_group_manager_added`, `license_user_group_manager_removed`, `license_user_group_assigned` Audit Log events"}

::ChangelogItem{type="added" description="`license_user_group.created`, `license_user_group.deleted`, `license_user_group.updated`, `license_user_group.license_user.manager_assigned` webhook events"}

::ChangelogItem{type="added" description="Stronger password validation for platform Users and License Users"}

::ChangelogItem{type="added" description="Account-based licensing UI: License Managers, Customer Accounts, and User Groups management with new tabs and navigation (LicenseManagerPage, CustomerAccount selectors, UserGroupsTab, LicensesTab, OrdersTab)"}

::ChangelogItem{type="added" description="Devices management: DevicesTab on LicenseUser and CustomerAccount pages, AllDevices page with expandable details and bulk actions (blacklist, whitelist, reset)"}

::ChangelogItem{type="added" description="Metadata fields: Metadata field with JSON validation on OrderManagerForm, UserGroup form, and License User creation form"}

::ChangelogItem{type="added" description="Improved backend error message display for password change and license user deletion"}

::ChangelogItem{type="added" description="Added columns for initial password, creation date, and total licenses on License Users tables"}

::ChangelogItem{type="added" description="Metadata filtering on UserGroupsPage, advanced/simple metadata filter conversion, new filters for license managers, customer accounts, and device status"}

::ChangelogItem{type="added" description="Updated labels, popups, and modals for clarity (e.g., License managers tab, confirmation dialogs, column headers)"}

::ChangelogItem{type="added" description="Devices route and sidebar shortcut, Users tab on Device page, license details on Device page"}

::ChangelogItem{type="added" description="Improved layout and style of MetadataFilter and various forms"}

::ChangelogItem{type="added" description="Improved alignment and consistency of icons, buttons, and tabs across pages"}

::ChangelogItem{type="fixed" description=" Devices tab and user group links navigation"}

::ChangelogItem{type="fixed" description="Confirmation popups and filter naming for customer account and licenses"}

::ChangelogItem{type="fixed" description="Search and small UI issues on LicenseUser and Device pages"}

::ChangelogItem{type="fixed" description="State preservation for metadata filters"}
:::

:::Changelog{title="v3.226.0 (17.06.2025.)"}
::ChangelogItem{type="added" description="Management API: `allow_offline_activation` field to the License model"}

::ChangelogItem{type="added" description="Management API: `activation_type` field to the Device model"}

::ChangelogItem{type="added" description="Management API: `allow_offline_activation` field to the License Template model"}

::ChangelogItem{type="added" description="Webhook events now contain `initiator_id` and `initiator_type` fields"}

::ChangelogItem{type="added" description="Webhook event for unassigning License User from a License"}
:::

:::Changelog{title="v3.225.0 (10.06.2025.)"}
::ChangelogItem{type="added" description="Changed email notification policy variable label from `Set password URL` to `Include Password Setup Email`"}

::ChangelogItem{type="added" description="Management API:`license__order__customer_account` filter on listing Devices"}
:::

:::Changelog{title="v3.224.0 (26.05.2025.)"}
::ChangelogItem{type="fixed" description="Limit test email notification to logged in user email address"}

::ChangelogItem{type="added" description="Standardized CSV import and export files"}

::ChangelogItem{type="added" description="Management API: `license_managers__id` filter on listing Orders"}
:::

:::Changelog{title="v3.223.0 (26.05.2025.)"}
::ChangelogItem{type="added" description="User max activations on license policy and order create view"}

::ChangelogItem{type="added" description="Webhook events related to Device Variables"}

::ChangelogItem{type="added" description="Management API: `user_max_activations` field to the License Template model"}

::ChangelogItem{type="added" description="Management API: When assigning License Users to a License (bulk) `max_activations`, `total_activations`, `allow_unlimited_activations` can be set per user"}

::ChangelogItem{type="added" description="Management API: Endpoint for creating Device Variables"}

::ChangelogItem{type="fixed" description="Importing and exporting licenses from CSV"}
:::

:::Changelog{title="v3.222.0 (20.05.2025.)"}
::ChangelogItem{type="added" description="Custom field allowed values list"}

::ChangelogItem{type="added" description="License users export"}

::ChangelogItem{type="fixed" description="Order licenses view correctly displaying bundles"}

::ChangelogItem{type="added" description="Management API: Endpoint for exporting License Users related to a License"}

::ChangelogItem{type="added" description="Management API: Endpoint for listing License User Groups for License User"}

::ChangelogItem{type="added" description="Management API: `license_users__id`, `device_active`, `type` filters on listing Devices"}

::ChangelogItem{type="added" description="Management API: `description__icontains` filter on listing License User Groups"}

::ChangelogItem{type="added" description="Management API: `license_user_group` filter on listing Licenses"}

::ChangelogItem{type="fixed" description="Check constraint violations for `times_activated` and `total_consumptions` fields now return 400 instead of 500"}
:::

:::Changelog{title="v3.221.0 (07.05.2025.)"}
::ChangelogItem{type="added" description="License manager metadata"}

::ChangelogItem{type="added" description="Product version connection to License"}

::ChangelogItem{type="added" description="Consumptions related email notifications"}

::ChangelogItem{type="added" description="Webhook events related to installation files, product features, product custom fields, license product features and license custom fields"}

::ChangelogItem{type="added" description="Management API: Endpoints for working with product custom field enumerations"}

::ChangelogItem{type="added" description="Management API: Installation File object is returned inside a License object when retrieving a single license"}

::ChangelogItem{type="added" description="Management API: License User Group object is returned inside a License object when retrieving a single license"}

::ChangelogItem{type="added" description="Management API: Installation File object is returned inside a License Template object when listing and retrieving License Templates"}

::ChangelogItem{type="added" description="Management API: `product_custom_field_enums` list in response objects when retrieving and listing Product Custom Fields"}

::ChangelogItem{type="added" description="Management API: `customer__account__not` filter on listing Orders"}
:::

:::Changelog{title="v3.220.0 (22.04.2025.)"}
::ChangelogItem{type="added" description="Locked license policies (SKU)"}

::ChangelogItem{type="added" description="License Policy <> License connection"}

::ChangelogItem{type="fixed" description="Product version pagination"}

::ChangelogItem{type="fixed" description="Updated the address in default email footer"}

::ChangelogItem{type="added" description="Management API: Added `installation_file` and `is_sku` fields to the License Template model"}

::ChangelogItem{type="added" description="Management API: License Templates with `is_sku` set to `true` are not editable"}

::ChangelogItem{type="added" description="Management API: `is_sku` filter on listing License Templates"}

::ChangelogItem{type="added" description="Management API: `license_template__code`, `license_template__code__icontains` filters on listing Licenses"}
:::

:::Changelog{title="v3.219.0 (11.04.2025.)"}
::ChangelogItem{type="added" description="Added check constraints related to total activations and total consumptions"}

::ChangelogItem{type="added" description="Management API: Device whitelist endpoint (`/api/v1/devices/{id}/whitelist`)"}

::ChangelogItem{type="added" description="`Device whitelisted` audit log action"}

::ChangelogItem{type="fixed" description="Properly handle reset, blacklist and whitelist for devices on bundle licenses"}

::ChangelogItem{type="fixed" description="Ability to clear required version from installation file"}

::ChangelogItem{type="added" description="Notifications Settings tab for setting email footer"}

::ChangelogItem{type="added" description="Restriciton of 24h for license usage history export"}
:::

:::Changelog{title="v3.218.0 (08.04.2025.)"}
::ChangelogItem{type="added" description="Management API: CSV imports and exports for products and product features"}

::ChangelogItem{type="fixed" description="Only product features related to the license are sent in email notifications"}

::ChangelogItem{type="improved" description="Removed deprecated export_history endpoint (`/api/v1/licenses/export_history`)"}

::ChangelogItem{type="added" description="Added hideCustomFields and hideProductFeatures on user portal configuration"}

::ChangelogItem{type="fixed" description="Properly handle extra:feature-licensing value and allowed features"}

::ChangelogItem{type="fixed" description="Properly handle extra:feature-licensing total value for both activation and consumption"}

::ChangelogItem{type="fixed" description="Make 2147483647 the &#x22;unlimited&#x22; value for max activations"}
:::

:::Changelog{title="v3.217.0 (31.03.2025.)"}
::ChangelogItem{type="added" description="Management API: Validation on product short code to only accept alphanumeric characters, digits and dashes"}

::ChangelogItem{type="added" description="Endpoint to add managers to an order in bulk (`/api/v1/orders/{id}/add_managers`)"}

::ChangelogItem{type="added" description="New endpoint for exporting license histories (`/api/v1/license-histories/export`), old one (`/api/v1/licenses/export_history`) is set to be deprecated"}

::ChangelogItem{type="added" description="Product short code to all email notifications which contain product information"}

::ChangelogItem{type="added" description="Metadata filtering on listing license product features"}

::ChangelogItem{type="fixed" description="Maximum number of objects returned on listing endpoints is set to 1000 if `limit` query param is higher than 1000"}

::ChangelogItem{type="fixed" description="Licensespring logo displays properly in all email notifications"}

::ChangelogItem{type="added" description="Enabled trial days on Plan Type modal (excluding Free plan)"}

::ChangelogItem{type="added" description="Added bundle devices tab and logic for bundle license refresh file"}

::ChangelogItem{type="added" description="Disabled individual license refresh files inside bundles"}

::ChangelogItem{type="added" description="Displayed all pricing plans by default"}

::ChangelogItem{type="added" description="Allowed `-` character in short product codes"}

::ChangelogItem{type="added" description="Displayed `-` in product code info popup"}

::ChangelogItem{type="added" description="Added `hide_oauth_settings` option to hide OAuth form on platform"}

::ChangelogItem{type="fixed" description="Grouped OAuth manager permissions and sorted by label"}

::ChangelogItem{type="fixed" description="Corrected notifications feature toggle behavior"}

::ChangelogItem{type="fixed" description="Properly hid refresh button for bundle licenses"}

::ChangelogItem{type="fixed" description="Fixed bottom margin alignment on license managers page"}
:::

:::Changelog{title="v3.216.0 (05.03.2025.)"}
::ChangelogItem{type="fixed" description="Device reset now also clears floating_last_seen, floating_in_use and borrowed_until fields"}

::ChangelogItem{type="fixed" description="Enabled make perpetual checkbox on license, customer and customer Account oAuth"}

::ChangelogItem{type="fixed" description="Added minWidth prop to Selector component on add manager to license modal"}

::ChangelogItem{type="fixed" description="Bottom margin alignment selector with button on license-managers page"}
:::

:::Changelog{title="v3.214.0 (10.02.2025.)"}
::ChangelogItem{type="added" description="Added `is_trial` filter on listing licenses"}

::ChangelogItem{type="fixed" description="SSO identity provider creation"}

::ChangelogItem{type="added" description="`has_max_consumptions` and `license_type` filters on listing licenses"}

::ChangelogItem{type="added" description="Enabled trial support for subscription licenses"}

::ChangelogItem{type="added" description="Added bulk actions for enabling and deleting licenses"}

::ChangelogItem{type="fixed" description="Resolved issues with editing time-limited license policies"}

::ChangelogItem{type="fixed" description="Corrected handling of single product notification policies"}

::ChangelogItem{type="fixed" description="Corrected search bar height alignment on both the LicenseList and OrderList pages"}

::ChangelogItem{type="fixed" description="Fixed the border radius issue on bulk action buttons in the licenses list"}
:::

:::Changelog{title="v3.213.0 (23.01.2025.)"}
::ChangelogItem{type="added" description="Added endpoints for managing license manager permissions to the management API"}

::ChangelogItem{type="fixed" description="Validation check for unique code on license policies per product"}

::ChangelogItem{type="added" description="Customer Account object in Order objects when listing and retrieving Orders"}

::ChangelogItem{type="fixed" description="Prevented tab change when the email form is dirty in settings notifications"}

::ChangelogItem{type="added" description="Added SearchableCheckbox component and implemented it across all instances of product feature selection"}

::ChangelogItem{type="added" description="Introduced a placeholder option to the SearchableCheckbox component"}

::ChangelogItem{type="added" description="Integrated SearchableCheckbox in the &#x22;Add Product Features&#x22; modal"}
:::

:::Changelog{title="v3.212.0 (08.01.2025.)"}
::ChangelogItem{type="added" description="Replaced internal identity and access management with keycloak for license users"}

::ChangelogItem{type="added" description="Added `is_default` filter on license policies"}

::ChangelogItem{type="fixed" description="Removed scheduled consumptions reset for floating licenses and floating license product features"}

::ChangelogItem{type="added" description="Deletion of license users through management API"}
:::

:::Changelog{title="v3.211.0 (12.12.2024.)"}
::ChangelogItem{type="added" description="Added `product_short_code__in` to listing licenses"}

::ChangelogItem{type="added" description="Added `text__icontains` filter on listing license usage histories"}

::ChangelogItem{type="fixed" description="Fixed wrong error details on failed license product features update"}

::ChangelogItem{type="added" description="Added optional QR code attachment to email notifications"}

::ChangelogItem{type="added" description="Added customer search by company and reference in order creation form"}

::ChangelogItem{type="added" description="Added `product_feature` to all license related tables"}

::ChangelogItem{type="fixed" description="Removed alphanumeric validation from product name"}

::ChangelogItem{type="added" description="Added alphanumeric validation to product code"}
:::

:::Changelog{title="v3.210.0 (26.11.2024.)"}
::ChangelogItem{type="added" description="Added restriction to Product Name field to accept only letters and numbers"}

::ChangelogItem{type="fixed" description="Fixed license reset to inclued the `device_count` field"}
:::

:::Changelog{title="v3.209.0 (30.10.2024.)"}
::ChangelogItem{type="added" description="Added installation file deletion to management API"}

::ChangelogItem{type="fixed" description="Users redirected to platform instead of keycloak when verifying email"}
:::

:::Changelog{title="v3.208.0 (09.10.2024.)"}
::ChangelogItem{type="added" description="Added custom fields inside a product object on license retrieve"}

::ChangelogItem{type="improved" description="Expanded licenses import and export with more fields"}
:::

:::Changelog{title="v3.207.0 (19.09.2024.)"}
::ChangelogItem{type="added" description="Added user portal subdomains for enterprise companies"}

::ChangelogItem{type="added" description="Added `allow_negative_consumptions` for licenses and features"}

::ChangelogItem{type="improved" description="License manager can edit user first_name, last_name and phone on user portal"}
:::

:::Changelog{title="v3.206.0 (06.09.2024.)"}
::ChangelogItem{type="added" description="Added `feature_expired`, `feature_will_expire` email notifications and expanded all email notifications with new variables"}

::ChangelogItem{type="added" description="Added option to send test email notifications"}

::ChangelogItem{type="added" description="Added `api_key` query param to license check"}

::ChangelogItem{type="added" description="Added `product_short_code` filter to listing licenses"}

::ChangelogItem{type="added" description="Added `license__id` field to licenses CSV export"}

::ChangelogItem{type="fixed" description="Fixed custom fields pagination"}

::ChangelogItem{type="fixed" description="Fixed company users selector on notification policy form"}

::ChangelogItem{type="fixed" description="Fixed reset to defaults button on email configuration view"}

::ChangelogItem{type="fixed" description="Fixed License API keys pagination"}

::ChangelogItem{type="added" description="Allow selecting API key when fetching device refresh file"}

::ChangelogItem{type="fixed" description="Fixed license bundle deletion so that the corresponding individual licenses are also deleted"}

::ChangelogItem{type="added" description="Added optional `order__reference` field to licenses CSV import"}

::ChangelogItem{type="added" description="Added optional `key_length` and `alphabet` query params to license key generation"}
:::

:::Changelog{title="v3.205.0 (18.08.2024.)"}
::ChangelogItem{type="fixed" description="Fixed propagation of `max_activations` and `is_license_manager` to Existing User form when assigning license users"}

::ChangelogItem{type="added" description="Added `maintenance_period` to Create Order form"}
:::

:::Changelog{title="v3.204.0 (10.07.2024.)"}
::ChangelogItem{type="fixed" description="Fixed `Allow unlimited consumptions` label when editing product features"}

::ChangelogItem{type="added" description="Added `devices__os` and `devices__os__icontains` filters on listing licenses UI and Management API"}
:::

:::Changelog{title="v3.203.0 (08.07.2024.)"}
::ChangelogItem{type="fixed" description="`max_activations` are now available when assigning existing license user"}

::ChangelogItem{type="added" description="Added `Offline floating features` support"}

::ChangelogItem{type="fixed" description="Fixed User consent view"}

::ChangelogItem{type="added" description="Added `validity_period` to license policies"}

::ChangelogItem{type="added" description="Added `os` filter on listing devices"}

::ChangelogItem{type="fixed" description="Changed hardware keys validity from 10 to 40 years by default"}

::ChangelogItem{type="added" description="Added `license_users` list to license device details view"}
:::

:::Changelog{title="v3.202.0 (28.06.2024.)"}
::ChangelogItem{type="added" description="Replaced internal identity and access management with keycloak"}

::ChangelogItem{type="added" description="Added validity period to license policies"}

::ChangelogItem{type="added" description="Added product creation through management API"}
:::

:::Changelog{title="v3.199.0 (21.05.2024.)"}
::ChangelogItem{type="added" description="Acceping any case of `true` or `1` as true value and anything else as false value for boolean fields in CSV imports"}

::ChangelogItem{type="added" description="Added `license__allow_unlimited_activations`, `license__is_floating`, `license__is_floating_cloud`, `license__floating_users` to licenses CSV export"}

::ChangelogItem{type="added" description="Added `license__allow_unlimited_activations` to licenses CSV import"}

::ChangelogItem{type="added" description="Added `is_license_manager` filter when listing license users"}

::ChangelogItem{type="fixed" description="Fixed export licenses `product_id` param"}

::ChangelogItem{type="added" description="Added optional `allow_unlimited_activations` param on assigning license user"}

::ChangelogItem{type="added" description="Added support for assigning passwords when assigning users to license in a bulk"}
:::

:::Changelog{title="v3.198.0 (22.04.2024.)"}
::ChangelogItem{type="added" description="Added initial support for hardware key licensing"}
:::

:::Changelog{title="v3.197.0 (22.04.2024.)"}
::ChangelogItem{type="added" description="Added metadata filters"}

::ChangelogItem{type="added" description="Added `note` header to the licenses CSV export"}

::ChangelogItem{type="fixed" description="Webhook event data is now correctly sent in `order.updated` event"}
:::

:::Changelog{title="v3.196.0 (02.04.2024.)"}
::ChangelogItem{type="fixed" description="Fixed linceses import failing due to `enable_maintenance_period` field"}

::ChangelogItem{type="added" description="Added `order.updated`, `order.deleted` webhook events"}
:::

:::Changelog{title="v3.195.0 ( 19.03.2024. )"}
::ChangelogItem{type="fixed" description="Fixed downloading airgap policy file"}

::ChangelogItem{type="added" description="Added `license.updated`, `license.reset`, `license.deleted`, `license.deactivated` webhook events"}

::ChangelogItem{type="added" description="Added maintenance related fields to licenses csv exports"}

::ChangelogItem{type="improved" description="Expanded data sent with customer related events"}

::ChangelogItem{type="improved" description="Expanded portal configuration options lists with portal title and message"}

::ChangelogItem{type="added" description="Added `Search by device hostname` to user portal"}
:::

:::Changelog{title="v3.194.0 ( 06.03.2024. )"}
::ChangelogItem{type="fixed" description="Fixed `Edit license` form for trials with both `trial_days` and `validity_period` defined"}

::ChangelogItem{type="improved" description="Added `customer.updated` and `customer.deleted` webhook events"}

::ChangelogItem{type="fixed" description="Fixed customer accounts update"}

::ChangelogItem{type="improved" description="Added `Apple` provider to the Single Sign On"}
:::

:::Changelog{title="v3.193.0 ( 21.02.2024. )"}
::ChangelogItem{type="added" description="Added `Apple` provider to the Single Sign On"}
:::

:::Changelog{title="v3.192.0 ( 21.02.2024. )"}
::ChangelogItem{type="improved" description="Standardized csv export headers and added quotes to all fields"}

::ChangelogItem{type="fixed" description="Metadata from UI saved as JSON object"}

::ChangelogItem{type="fixed" description="Fixed bug where custom fields on license policy were deleted when policy was set as default"}

::ChangelogItem{type="fixed" description="Fixed auth logo style"}

::ChangelogItem{type="added" description="Added `Apple` provider to the Single Sign On"}
:::

:::Changelog{title="v3.191.0 ( 06.02.2024. )"}
::ChangelogItem{type="added" description="Added `Webhooks` service"}

::ChangelogItem{type="added" description="Added `Add new customer` button on `Order details` view"}

::ChangelogItem{type="improved" description="Simplified SSO settings for SAML providers"}
:::

:::Changelog{title="v3.190.0 (21.11.2023)"}
::ChangelogItem{type="improved" description="Added maintenance expiration date to maintenance_will_expire email notification"}

::ChangelogItem{type="improved" description="Added `autofocus` and `Enter` keyup listener on authentification forms"}

::ChangelogItem{type="improved" description=" Added `Select existing manager` option when adding license manager to the order"}

::ChangelogItem{type="improved" description="Added `Delete` option on license manager page"}

::ChangelogItem{type="improved" description="Added `remove_lm_permissions` endpoint which removes all license manager definitions from a user"}

::ChangelogItem{type="improved" description="Properly handled `Max simultaneous license users` when editing a license with active floating devices"}

::ChangelogItem{type="improved" description="Added license total consumptions reset button to the License details view"}

::ChangelogItem{type="improved" description="CRUD endpoints for license product features with audit logs"}

::ChangelogItem{type="fixed" description="Added backend validation for license custom fields - license and product custom field must be unique together"}
:::

:::Changelog{title="v3.189.0 (07.11.2023)"}
::ChangelogItem{type="fixed" description="`maxActivationsDevices` error when editing license"}

::ChangelogItem{type="added" description="Added `floating features`"}

::ChangelogItem{type="improved" description=" Added `metadata` to customer accounts"}

::ChangelogItem{type="improved" description="Added floating support on license features"}

::ChangelogItem{type="improved" description="Added licenses export"}

::ChangelogItem{type="improved" description="Added created_at filters on listing licenses"}

::ChangelogItem{type="fixed" description="License reset also resets the transfers count"}
:::

:::Changelog{title="v3.188.0 (25.09.2023)"}
::ChangelogItem{type="improved" description="Added documentation widget to the platform"}

::ChangelogItem{type="improved" description="Expanded Integrations tab with detailed activation UI for each integration"}
:::

:::Changelog{title="v3.187.0 (05.09.2023)"}
::ChangelogItem{type="added" description="Added ability to update Customer on Order"}

::ChangelogItem{type="added" description="Added ability to update Order on License"}

::ChangelogItem{type="fixed" description="Added a limit of 100 licenses for bulk update"}

::ChangelogItem{type="added" description="Added `devices__hostname` and `devices__hostname__icontains` on listing licenses"}

::ChangelogItem{type="fixed" description="Fixed allow unlimited consumptions toggle on license product feature template not applying"}
:::

:::Changelog{title="v3.186.0 (02.08.2023)"}
::ChangelogItem{type="fixed" description="Fixed overwritting license manager permissions when adding products"}
:::

:::Changelog{title=" v3.184.0 (27.07.2023)"}
::ChangelogItem{type="fixed" description="Fixed Prevent device transfers setter"}

::ChangelogItem{type="fixed" description="On license deletion also delete order item if empty"}

::ChangelogItem{type="fixed" description="Properly check max allowed when assigning license users"}

::ChangelogItem{type="fixed" description="Fix crash when parsing improper installation file versions"}
:::

:::Changelog{title="v3.183.0 (18.07.2023)"}
::ChangelogItem{type="added" description="Added endpoints for adding and removing product features to/from all licenses under related product"}

::ChangelogItem{type="improved" description="Removed legacy disabled_user field from the UI"}

::ChangelogItem{type="added" description="Added Issued licenses and Remaining licenses per product list on license manager page if Distribution portal is enabled"}

::ChangelogItem{type="added" description="Added max number of licenses each manager can create per product"}

::ChangelogItem{type="improved" description=" License manager can select the number of licenses to issue when creating order on Distribution portal"}

::ChangelogItem{type="added" description="Added sorting by customer_account__name on customers"}

::ChangelogItem{type="fixed" description="Fixed sorting customer by customer account name"}

::ChangelogItem{type="added" description="Added a warning when product does not have a default license policy defined"}

::ChangelogItem{type="fixed" description=" Selected tab on product page will not be reset on the default one after adding features"}
:::

:::Changelog{title="v3.182.0 (06.07.2023)"}
::ChangelogItem{type="added" description="Added Mgmgt API logs to the audit log UI"}

::ChangelogItem{type="fixed" description=" Fixed adding more than 1 floating user when unlimited license activations selected"}

::ChangelogItem{type="improved" description="Generate ids as snowflakes when importing licenses, order items and orders"}

::ChangelogItem{type="added" description="Added support for air gap deactivation"}

::ChangelogItem{type="fixed" description=" Resolved permission related bug on UI when accessing customers and notification policies"}

::ChangelogItem{type="fixed" description="Fixed missing LicenseSpring logo image on password reset pages"}

::ChangelogItem{type="fixed" description="Fixed installation file required version parsing"}

::ChangelogItem{type="added" description="Added management api key calls to audit log"}
:::

:::Changelog{title="v3.181.0 (01.06.2023)"}
::ChangelogItem{type="fixed" description="Fixed customer metadata validation"}

::ChangelogItem{type="improved" description="Changed stripe invoices limit from 10 to 100"}

::ChangelogItem{type="added" description="Added json string validation"}

::ChangelogItem{type="added" description="Added stripe key in api key info response"}

::ChangelogItem{type="fixed" description="Fixed offline actions"}

::ChangelogItem{type="added" description="Implemented generic integrations"}

::ChangelogItem{type="added" description="Added stripe invoices exception for companies without stripe customer"}

::ChangelogItem{type="fixed" description="Fixed metadata not being set when nested in requests"}

::ChangelogItem{type="fixed" description="Fixed 404 on invoices endpoint"}

::ChangelogItem{type="fixed" description="Fixed some filters which were not working because of package update"}

::ChangelogItem{type="fixed" description="Fxed 404 errors on endpoints with legacy core api"}

::ChangelogItem{type="fixed" description="Fixed authtoken on cognito"}

::ChangelogItem{type="fixed" description="Replaced method not allowed with permission denied exception where appropriate"}

::ChangelogItem{type="fixed" description="Fixed installation file filename handling"}

::ChangelogItem{type="added" description="Added metadata fields to models"}

::ChangelogItem{type="added" description="Added ping endpoint"}

::ChangelogItem{type="added" description="Added subscription_id filter to licenses"}

::ChangelogItem{type="added" description="Added api key info endpoint"}

::ChangelogItem{type="fixed" description="Fixed offline action api key check"}
:::

:::Changelog{title="v3.179.0 (28.02.2023)"}
::ChangelogItem{type="added" description="Added max_license_users and license_users_left_to_assign to related notifications"}

::ChangelogItem{type="fixed" description="Fixed duplicate license_custom_fields on licenses export"}

::ChangelogItem{type="added" description="Added updated_at filter on listing licenses"}

::ChangelogItem{type="added" description="Added management_api_key_info endpoint"}

::ChangelogItem{type="added" description="Added maintenance period and max number of license users email notifications"}
:::

:::Changelog{title=" v3.175.0"}
::ChangelogItem{type="added" description="Added Delete order endpoint to Management API"}

::ChangelogItem{type="added" description="Added extra:multiple-api-keys company feature"}
:::

:::Changelog{title="v3.172.0 (17.01.2023)"}
::ChangelogItem{type="added" description="Added Assign permissions template to user label action on All Users list"}

::ChangelogItem{type="added" description="Display email_sender field on Emails tab where applicable"}

::ChangelogItem{type="added" description="Added User labels filter on Audit log list"}

::ChangelogItem{type="added" description=" Added grace_period to subscription licenses"}

::ChangelogItem{type="added" description="Extended License api/shared keys - multiple api/shared keys per account, allowed products option, labels, read_only and revoked fields."}

::ChangelogItem{type="improved" description="Audit log expanded with platform_user and user_permission_template events"}

::ChangelogItem{type="fixed" description="Fixed clear filters button on Licenses list"}
:::

:::Changelog{title="v3.170.0 (02.01.2023)"}
::ChangelogItem{type="fixed" description="Search by name when issuing licenses now returns customer first and last name instead of email"}

::ChangelogItem{type="fixed" description="Fixed multi sort on tables"}

::ChangelogItem{type="added" description="Implemented unlimited activations and consumptions for licenses and license features"}
:::

:::Changelog{title="v3.169.0 (20.12.2022)"}
::ChangelogItem{type="fixed" description="Customer duplicate email check"}
:::

:::Changelog{title="v3.163.0 (28.11.2022)"}
::ChangelogItem{type="fixed" description="Fixed editing license product features on vendor platform"}

::ChangelogItem{type="fixed" description="Remove devices hardware id from generic licenses search"}

::ChangelogItem{type="fixed" description="Send companyID on patchUser endpoint"}
:::

:::Changelog{title="v3.162.0 (23.11.2022)"}
::ChangelogItem{type="fixed" description="Send companyID on patchUser endpoint"}
:::

:::Changelog{title="v3.161.0 (22.11.2022)"}
::ChangelogItem{type="improved" description="/offline is redirected to offline.licensespring.com domain and /air-gap to airgap.licensespring.com"}

::ChangelogItem{type="fixed" description="Prevent whole product page refresh on successfull change"}

::ChangelogItem{type="improved" description=" Use separate endpoint for blacklisting devices&#xA;Mngmnt API: Analytics endpoints"}

::ChangelogItem{type="improved" description="Added Audit log standalone page and inline as a section on license, order, product and customer details view"}

::ChangelogItem{type="improved" description="License details tab is refreshed on every visit"}

::ChangelogItem{type="improved" description="Added Search by device hardware_id filter on License list"}
:::

:::Changelog{title="v3.160.0 (08.11.2022)"}
::ChangelogItem{type="improved" description="Enable removing platform users"}

::ChangelogItem{type="fixed" description="Max limit as 100 set on list licenses endpoint"}
:::

:::Changelog{title="v3.158.0 (12.10.2022)"}
::ChangelogItem{type="improved" description="Removed inactive users from notification policies"}

::ChangelogItem{type="improved" description="Added user permissions and permissions checks on the platform"}

::ChangelogItem{type="improved" description="Added user labels"}

::ChangelogItem{type="improved" description="Added ?sso query to enable automatic sso login hosted UI display"}
:::

:::Changelog{title="v3.157.0 (20.09.2022)"}
::ChangelogItem{type="improved" description="Added SSO code auth flow"}

::ChangelogItem{type="improved" description="Added Okta SSO provider"}
:::

:::Changelog{title="v3.156.0 (30.08.2022)"}
::ChangelogItem{type="fixed" description="Fixed setting company_name on a new customer when creating order in the platform"}

::ChangelogItem{type="improved" description="Fixed deleting phone number from customer"}

::ChangelogItem{type="improved" description="Added Max activations column on licenses list inside order view"}

::ChangelogItem{type="improved" description=" Added Auth0 as a Single Sign On provider"}

::ChangelogItem{type="fixed" description="Fixed max_overages not nullable bug on ProductFeatures"}

::ChangelogItem{type="fixed" description="Fixed total_consumptions field on /update_features endpoint"}

::ChangelogItem{type="improved" description="Added Reports tab in Analytics view with License API call count per licenses, orders and customers"}
:::

:::Changelog{title="v3.154.0 (04.08.2022)"}
::ChangelogItem{type="improved" description="License enable/disable endpoints change only enabled field on the license"}

::ChangelogItem{type="improved" description="Added device_id and id to the license response on check_license and activate_license"}
:::

:::Changelog{title="v3.152.0 (13.07.2022)"}
::ChangelogItem{type="improved" description="Added max_activations and total_activations to license users"}
:::

:::Changelog{title="v3.151.0 (05.07.2022)"}
::ChangelogItem{type="improved" description="Fix inconsistencies between air-gap license policy file and license activation response"}

::ChangelogItem{type="improved" description="Use new update-features endpoint for add/edit/delete license features"}

::ChangelogItem{type="improved" description="License users can set initial password with activation URL"}
:::

:::Changelog{title="v3.149.0 (13.06.2022)"}
::ChangelogItem{type="improved" description="Return company_name on customer in UI and Management API"}

::ChangelogItem{type="improved" description="Added feature consumption activity analytics"}
:::

:::Changelog{title="v3.142.0 (07.06.2022.)"}
::ChangelogItem{type="improved" description="Added support for product bundles"}

::ChangelogItem{type="fixed" description="Fix platform crash when trying to create air-gap license when no products with air-gap policies are defined"}

::ChangelogItem{type="improved" description="Add create_bundle_order license manager permission for enterprise pricing plan"}
:::

:::Changelog{title="v3.140.0 (10.05.2022.)"}
::ChangelogItem{type="improved" description="Use new /borrow, /borrow-release, disable and /enable endpoints on platform and user portal"}

::ChangelogItem{type="improved" description="Added Export customers form on customers list"}

::ChangelogItem{type="improved" description="Added Export usage report form on license usage report tab"}

::ChangelogItem{type="improved" description="Add Search by all search type to Customers, Customer accounts, Orders and Licenses list views"}

::ChangelogItem{type="improved" description="Add customer account reference field and reference filters on account, licenses and orders search"}

::ChangelogItem{type="improved" description="Show Licenses tab on customer account view"}
:::

:::Changelog{title="v3.137.0 (26.4.2022)"}
::ChangelogItem{type="improved" description="Expand user portal configuration with Allow users to borrow licenses"}

::ChangelogItem{type="improved" description="Added new License has activated notification policy"}

::ChangelogItem{type="improved" description="Notification policy events expanded with new license detail fields"}
:::

:::Changelog{title="v3.136.0 (12.4.2022.)"}
::ChangelogItem{type="improved" description="Check for existing order ID on the first step of the order create form"}

::ChangelogItem{type="improved" description=" Added notify_customer field to notification policy events"}
:::

:::Changelog{title="v3.133.0 (29.3.2022.)"}
::ChangelogItem{type="improved" description=" Implemented license borrowingform"}

::ChangelogItem{type="improved" description="Enable editing redirect_uri for customer account Single Sign On user pool"}

::ChangelogItem{type="added" description="Management API: Borrow license"}

::ChangelogItem{type="added" description="Management API: Merge customers"}

::ChangelogItem{type="fixed" description=" Fixed settings query params when 4 tabs displayed"}
:::

:::Changelog{title="v3.132.0 (15.3.2022.)"}
::ChangelogItem{type="improved" description=" Added optional customer_email field to email notifications"}

::ChangelogItem{type="fixed" description=" Fixed issuing new licenses on existing order"}

::ChangelogItem{type="added" description="Added new analytics events: single_sign_on and get_device_variables"}
:::

:::Changelog{title="v3.131.0 (1.3.2022.)"}
::ChangelogItem{type="improved" description=" Added Prevent device transfers to license"}

::ChangelogItem{type="improved" description=" Added customer account SSO management"}

::ChangelogItem{type="fixed" description="Fixed a bug where trial related notifications are not being sent"}

::ChangelogItem{type="fixed" description="Fixed a bug where wrong plan type is sent in trial expiration email"}

::ChangelogItem{type="fixed" description="Send check_days with trial_will_expire notification policies"}

::ChangelogItem{type="improved" description=" Fallback to customer name when email not available on customer selector"}

::ChangelogItem{type="improved" description="Added search selector next to customer selector on manual order create view: Search by email and Search by name"}

::ChangelogItem{type="improved" description="Support creating orders without customers"}
:::

:::Changelog{title="v3.130.0 (15.02.2022.)"}
::ChangelogItem{type="improved" description=" Support start_date on the license ( License cannot be activated before this date )"}

::ChangelogItem{type="improved" description="Support trial_created, trial_expired and trial_will_expire notification event templates"}
:::

:::Changelog{title="v3.129.0 (01.02.2022.)"}
::ChangelogItem{type="improved" description="  Displayed Number of licenses on product details view"}

::ChangelogItem{type="improved" description="Added Product license filter"}

::ChangelogItem{type="improved" description="Added Expires before date license filter returning all licenses with validity_period between current date and selected date"}
:::

:::Changelog{title="v3.128.0 (18.01.2022.)"}
::ChangelogItem{type="improved" description=" Add allow_offline_floating_cloud company settings"}

::ChangelogItem{type="improved" description="Display detailed error notification on failed order create"}

::ChangelogItem{type="improved" description="Add default set of license manager permissions per company"}
:::

:::Changelog{title="v3.127.0 (05.01.2022.)"}
::ChangelogItem{type="improved" description="Expand license policies with allow_trial and trial_days"}
:::

:::Changelog{title="v3.126.0 (23.12.2021.)"}
::ChangelogItem{type="improved" description="Fixed bug on product selector login in Issue licenses view"}

::ChangelogItem{type="improved" description="Added license managers permissions and action report on manager details view"}

::ChangelogItem{type="added" description="Management API: More filters when listing licenses"}

::ChangelogItem{type="added" description="Management API: License objects expanded with product_custom_fields"}
:::

:::Changelog{title="v3.125.0 (30.11.2021.)"}
::ChangelogItem{type="improved" description="Added license_custom_fields on licenses export"}

::ChangelogItem{type="improved" description="Added Order reference in notification on order creation"}

::ChangelogItem{type="improved" description="management API Edit order endpoint"}

::ChangelogItem{type="improved" description="Added Edit order form on order details view"}

::ChangelogItem{type="fixed" description="Fix change customer account button label"}

::ChangelogItem{type="improved" description="Implement vendor platform Single Sign On for enterprise companies"}
:::

:::Changelog{title="v3.124.0 (16.11.2021.)"}
::ChangelogItem{type="fixed" description="Fixed editing subscription license via platform"}

::ChangelogItem{type="improved" description="Implemented account based licensing using Customer accounts"}

::ChangelogItem{type="improved" description=" Add customer form on customers list view"}

::ChangelogItem{type="improved" description="management API Customer accounts endpoints"}

::ChangelogItem{type="improved" description="Add resizable table columns"}
:::

:::Changelog{title="v3.122.0 (03.11.2021.)"}
::ChangelogItem{type="fixed" description="Use constant source of countries list"}

::ChangelogItem{type="fixed" description="Changed products list and filters in line with license policies fields"}

::ChangelogItem{type="fixed" description=" Use custom values selector fixed to use currently selected license policy"}

::ChangelogItem{type="fixed" description="Bug fixes on the platform ( resend notification when policy missing, remove user cleanup effect )"}
:::

:::Changelog{title="v3.121.0 (19.10.2021. )"}
::ChangelogItem{type="improved" description="Expand licenses list variables in email templates with custom fields"}

::ChangelogItem{type="improved" description="Added resend notification capabilities"}

::ChangelogItem{type="improved" description=" Added management API endpoints for license user"}

::ChangelogItem{type="fixed" description="Fix charge and invoice notifications"}

::ChangelogItem{type="fixed" description="Fix license expiration calculation logic"}

::ChangelogItem{type="fixed" description="Removed autocomplete from 2FA code input"}

::ChangelogItem{type="fixed" description="Fix product feature form unique code validation method"}

::ChangelogItem{type="fixed" description="Fix product selector bug on order issuing view"}

::ChangelogItem{type="improved" description="Added management API endpoints for customer labels"}
:::

:::Changelog{title="v3.120.0 (06.10.2021.)"}
::ChangelogItem{type="fixed" description="Bug fixes"}

::ChangelogItem{type="improved" description="Implemented notifications module"}

::ChangelogItem{type="improved" description="Email configuration view added to the platform"}
:::

:::Changelog{title="v3.113.0 (07.09.2021.)"}
::ChangelogItem{type="improved" description="Added license policies"}

::ChangelogItem{type="fixed" description="Consent form URLs fixed"}

::ChangelogItem{type="improved" description="Simplified product creation in platform"}
:::

:::Changelog{title="v3.112.0 (27.07.2021.)"}
::ChangelogItem{type="improved" description=" Added Download license refresh file button to Device details to be used to refresh offline local license file"}

::ChangelogItem{type="fixed" description="Fixed unassigning users from licenses"}
:::

:::Changelog{title="v3.110.0 (13.07.2021.)"}
::ChangelogItem{type="improved" description="Added Channel to product versions"}
:::

:::Changelog{title="v3.109.0 (28.06.2021.)"}
::ChangelogItem{type="fixed" description="Monthly rate limit bar bug fixed"}

::ChangelogItem{type="fixed" description="License manager delete button bug fix"}
:::

:::Changelog{title="v3.108.0 (22.06.2021.)"}
::ChangelogItem{type="improved" description="Implement Analytics v1 feature on Dashboard, License and Analytics page"}

::ChangelogItem{type="improved" description="Display User column on the License Devices tab if license product is user based"}
:::

:::Changelog{title="v3.107.0 (16.06.2021.)"}
::ChangelogItem{type="improved" description="Added Allow users to reset licenses to user portal configuration"}
:::

:::Changelog{title="v3.105.0 (01.06.2021.)"}
::ChangelogItem{type="improved" description=" Added license product features import"}
:::

:::Changelog{title="v3.105.0 (25.05.2021.)"}
::ChangelogItem{type="improved" description=" Add release_date and product_details to license_check response"}
:::

:::Changelog{title="v3.103.0 (18.05.2021.)"}
::ChangelogItem{type="improved" description=" Added max_transfers field on License"}

::ChangelogItem{type="improved" description="Redesign Requires version field on Product versions UI"}
:::

:::Changelog{title="v3.102.0 (10.05.2021. )"}
::ChangelogItem{type="improved" description=" Add requires_version field on product versions to support intermediate updates"}

::ChangelogItem{type="improved" description="Add overages and consumption resets on product features"}

::ChangelogItem{type="improved" description="Licenses import tab view on licenses list"}

::ChangelogItem{type="fixed" description="Bug fix on license usage report details click"}

::ChangelogItem{type="improved" description="Customers import tab view on customers list"}
:::

:::Changelog{title="v3.101.0 (28.04.2021.)"}
::ChangelogItem{type="improved" description=" Product feature codes limit raised to 50 chars max"}

::ChangelogItem{type="improved" description="Add product version delete feature to the platform"}

::ChangelogItem{type="improved" description="Display event data from integrations inside Usage report row"}

::ChangelogItem{type="improved" description="Customer tab removed from license view"}

::ChangelogItem{type="improved" description="CSV licenses import"}

::ChangelogItem{type="improved" description="mngmnt API Customer reference filter"}

::ChangelogItem{type="improved" description="Add reference to Consumers list view"}

::ChangelogItem{type="improved" description="Add Batch license assign form to License users view"}

::ChangelogItem{type="fixed" description="Encode emails inside search query"}

::ChangelogItem{type="improved" description="CSV orders import"}
:::

:::Changelog{title="v3.99.0 (20.04.2021.)"}
::ChangelogItem{type="improved" description="Enable traversing selector options using keyboard, expand DateInput with close-on-outside-click, add PhoneNumberInput component"}
:::

:::Changelog{title="v3.98.0 (13.04.2021.)"}
::ChangelogItem{type="improved" description="License object returned on devices endpoints"}

::ChangelogItem{type="improved" description="Whitelabel logo in emails"}

::ChangelogItem{type="improved" description="Add description to Subscription duration label on product views"}
:::

:::Changelog{title="v3.97.0 (06.04.2021.)"}
::ChangelogItem{type="fixed" description="Display Max simultaneous users value as N/A for non floating licenses on license list"}

::ChangelogItem{type="improved" description="Count License transactions with datetime filters"}

::ChangelogItem{type="improved" description="Disable / enable licenses through the platform only changes enabled field on a license, leaving device status as it was"}
:::

:::Changelog{title="v3.96.0 (30.03.2021. )"}
::ChangelogItem{type="fixed" description="Fix unlimited max_license_users validation"}

::ChangelogItem{type="fixed" description="Enable logout for disabled users"}

::ChangelogItem{type="improved" description="Add Order reference field to the create order form and move Customer reference to new customer view"}

::ChangelogItem{type="improved" description="Expand product page title with copy button and short code as description"}

::ChangelogItem{type="improved" description="Add Transfer count field to the license details table"}

::ChangelogItem{type="improved" description="Expand orders export with reference and all customer fields"}
:::

:::Changelog{title="v3.95.0 (23.03.2021.)"}
::ChangelogItem{type="improved" description="Added license floating timeout field to order create and license edit"}

::ChangelogItem{type="improved" description="Display used product features count on Product view - Features tab"}

::ChangelogItem{type="fixed" description="Display subscription notice instead of duration fields when creating and editing subscription licenses"}

::ChangelogItem{type="improved" description="Added Is disabled selector to license list filters"}
:::

:::Changelog{title="v3.92.0 (09.03.2021.)"}
::ChangelogItem{type="fixed" description="Fix expiry date validation when editing product features on licenses edit"}

::ChangelogItem{type="fixed" description="Use proper is_license_manager field on license users"}
:::

:::Changelog{title="v3.91.0 (02.03.2021.)"}
::ChangelogItem{type="improved" description="subscription type notice is dismissible"}

::ChangelogItem{type="fixed" description="Fix z-index values on Page notice and Filter selector labels"}

::ChangelogItem{type="improved" description=" Added date range picker to license usage report"}

::ChangelogItem{type="improved" description="Expand user portal configuration with option to show product download links on portal"}
:::

:::Changelog{title="v3.89.0 (23.02.2021.)"}
::ChangelogItem{type="improved" description="Added subscription license type notice on license details and order create views"}

::ChangelogItem{type="improved" description="Added additional installation file / version fields to platform UI"}
:::

:::Changelog{title="v3.88.0 (17.02.2021.)"}
::ChangelogItem{type="fixed" description="Prevent virtual machine form field on edit license form"}

::ChangelogItem{type="improved" description="eula_link, release_notes_link, size on installation file"}
:::

:::Changelog{title="v3.87.0 (16.02.2021. )"}
::ChangelogItem{type="fixed" description="Display Floating timeout only for enterprise users"}

::ChangelogItem{type="improved" description="Time-limited product features implemented using Expiry date"}
:::

:::Changelog{title="v3.86.0 (09.02.2021.)"}
::ChangelogItem{type="improved" description="Filter products by short code"}

::ChangelogItem{type="improved" description="Add tooltip to Expiration Date header with additional information"}

::ChangelogItem{type="improved" description="Validate product feature code - needs to be unique on product"}

::ChangelogItem{type="improved" description="Add search by customer email to licenses list"}

::ChangelogItem{type="improved" description="Product feature groups model and endpoints"}

::ChangelogItem{type="improved" description="Export order data from order details page"}
:::

:::Changelog{title="v3.85.0 (02.02.2021.)"}
::ChangelogItem{type="improved" description="Management API for Device variables"}

::ChangelogItem{type="improved" description="User portal email templates updated"}

::ChangelogItem{type="improved" description="Added label to management API keys"}

::ChangelogItem{type="fixed" description="Customer emails are all lowercase"}

::ChangelogItem{type="improved" description="Added Orders to User Portal"}
:::

:::Changelog{title="v3.84.0 (26.01.2021.)"}
::ChangelogItem{type="improved" description="Product features can now be deleted from products"}
:::

:::Changelog{title="v3.83.0 (19.01.2021.)"}
::ChangelogItem{type="fixed" description="changing max activations below total active devices count"}

::ChangelogItem{type="improved" description="management API: Resetting and blacklisting devices"}

::ChangelogItem{type="improved" description="Show Disabled on for disabled licenses, hide expiration date when disabled"}

::ChangelogItem{type="improved" description="Added hyperlink to the changelog from platform version label on the sidebar"}

::ChangelogItem{type="fixed" description="Encode emails as params in network requests"}

::ChangelogItem{type="improved" description="mgmt API: Set Password for user per email address"}
:::

:::Changelog{title="v3.82.0 (12.01.2021.)"}
::ChangelogItem{type="improved" description="Added order reference field to the order view"}

::ChangelogItem{type="improved" description="Implemented product custom fields update form"}

::ChangelogItem{type="improved" description="Implemented new create order endpoint -> /api/v1/orders/create_order/"}

::ChangelogItem{type="improved" description="Added optional Is customer license manager checkbox field to order creation form"}
:::

:::Changelog{title="v3.81.0 (05.01.2021.)"}
::ChangelogItem{type="improved" description="management API for Product and License custom fields"}

::ChangelogItem{type="fixed" description="Fixed bug when deleting order with active licenses"}

::ChangelogItem{type="improved" description="Expanded user portal configuration with sidebar and page background color"}
:::

:::Changelog{title="v3.80.0 (22.12.2020.)"}
::ChangelogItem{type="improved" description="Send email to managers upon assignment"}

::ChangelogItem{type="improved" description="Optional Set end date field on subscription licenses (validity_period)"}

::ChangelogItem{type="fixed" description="Fix creating order manager from order customer"}

::ChangelogItem{type="improved" description="Added hidden password field with copy button"}

::ChangelogItem{type="fixed" description="Active devices >= check"}

::ChangelogItem{type="improved" description="Added collapsible sidebar"}

::ChangelogItem{type="fixed" description="Acount user status set active per company"}

::ChangelogItem{type="improved" description="Expanded user portal configuration with top header background color"}
:::

:::Changelog{title="v3.78.0 (16.12.2020.)"}
::ChangelogItem{type="improved" description="mngmnt API set_password for license users"}

::ChangelogItem{type="improved" description="License usage report"}

::ChangelogItem{type="improved" description=" Added company logo upload to User portal configuration view"}
:::

:::Changelog{title="v3.76.0 (8.12.2020.)"}
::ChangelogItem{type="improved" description="Update product features and custom fields UI"}
:::

:::Changelog{title="v3.75.0 (01.12.2020.)"}
::ChangelogItem{type="added" description="Multiple mgmt API keys per account"}

::ChangelogItem{type="added" description="Changed data model to have m2m License-LicenseUser"}

::ChangelogItem{type="improved" description="User can change custom fields when creating order"}
:::

:::Changelog{title="v3.69.0 (10.11.2020.)"}
::ChangelogItem{type="fixed" description="Fixed edit license validation bug"}

::ChangelogItem{type="fixed" description="Include archived products check to product name validation"}

::ChangelogItem{type="improved" description="Show list of archived products and enable product reactivation"}

::ChangelogItem{type="improved" description="Added license note field (sort, search, edit)"}

::ChangelogItem{type="added" description="Expose the Management API to allow adding new product versions"}

::ChangelogItem{type="fixed" description="Implement duration/period sync in Edit license form"}
:::

:::Changelog{title="v3.68.0 (04.11.2020.)"}
::ChangelogItem{type="improved" description="Edit license form redesigned as a slide pane"}

::ChangelogItem{type="improved" description="Product configuration redesigned as a multi step form"}

::ChangelogItem{type="fixed" description="Sending email on order create"}
:::

:::Changelog{title="v3.67.0 (28.10.2020.)"}
::ChangelogItem{type="fixed" description="Consent form checkboxes bug fixed"}

::ChangelogItem{type="fixed" description="Prevent links to unavailable linked company accounts"}
:::

:::Changelog{title="v3.66.0 (27.10.2020.)"}
::ChangelogItem{type="improved" description="Added Linked Accounts feature"}

::ChangelogItem{type="fixed" description="Ordering licenses by product id and ordering orders by customer attributes"}

::ChangelogItem{type="fixed" description="Use product.product_name field instead of product.id on licences list"}
:::

:::Changelog{title="v3.65.0 (22.10.2020.)"}
::ChangelogItem{type="improved" description="Added Linked Accounts feature"}

::ChangelogItem{type="fixed" description="Ordering licenses by product id and ordering orders by customer attributes"}

::ChangelogItem{type="fixed" description="Use product.product_name field instead of product.id on licences list"}
:::

:::Changelog{title="v3.62.0 (20.10.2020.)"}
::ChangelogItem{type="fixed" description="Updated file hash label with algorithm description - MD5"}

::ChangelogItem{type="fixed" description="Updating maintenance_period when maintenance_duration changes if time_activated is set"}

::ChangelogItem{type="fixed" description="Trim orders responses for faster load time"}

::ChangelogItem{type="improved" description="Enable creation of dev companies (enterprise or standard with no trial and no subscription)"}

::ChangelogItem{type="improved" description="Fixed bug with inability to disable / re-enable a binary version for a product"}

::ChangelogItem{type="fixed" description="allow_sdk_password_change field on Company"}

::ChangelogItem{type="improved" description="Added customer labels sorting and filters to license list, orders list and customers list. Expanded labels with colors and created new Customer labels tab"}

::ChangelogItem{type="improved" description="Add license managers list on Account > User portal configuration page"}

::ChangelogItem{type="improved" description="Licenses, orders and customers are orderable by customer labels"}

::ChangelogItem{type="improved" description="first name, last name, phone number filters on license users"}

::ChangelogItem{type="fixed" description="license key in one line on the email table&#xA;"}
:::

:::Changelog{title="v3.61.0 (5.10.2020. )"}
::ChangelogItem{type="fixed" description="Fix date range filter on export form"}

::ChangelogItem{type="fixed" description="Fix customer info on orders export"}

::ChangelogItem{type="improved" description="Filter license user by is_manager"}

::ChangelogItem{type="fixed" description="added company ID to all 'license-user' endpoint requests"}
:::

:::Changelog{title="1.10.2020."}
::ChangelogItem{type="fixed" description="Fix license list pagination when using search by order ID query"}
:::

:::Changelog{title="23.09.2020."}
::ChangelogItem{type="improved" description="Product object with id and product_name in Licenses response"}

::ChangelogItem{type="improved" description="Sending info with order details on order creation to customer email"}
:::

:::Changelog{title="18.09.2020."}
::ChangelogItem{type="improved" description="Added 'Send license keys to customer email' settings option"}

::ChangelogItem{type="improved" description="New data column in Licenses list: &#x22;Active Devices Up to Date&#x22;"}
:::

:::Changelog{title="14.09.2020."}
::ChangelogItem{type="fixed" description="Use company ID as param with license device endpoints"}

::ChangelogItem{type="fixed" description="Use product feature code instead of ID when patching license product features"}

::ChangelogItem{type="fixed" description="Added pagination to all remaining tables"}

::ChangelogItem{type="improved" description="Expand sentry error logs with additional data"}

::ChangelogItem{type="fixed" description="Use product features codes instead of our internal IDs when setting license product features"}
:::

:::Changelog{title="v3.60.0 (7.9.2020.)"}
::ChangelogItem{type="added" description="management API generate_license and create_order endpoints"}
:::

:::Changelog{title="28.08.2020."}
::ChangelogItem{type="fixed" description="Changed label for sending out user-based activation emails in settings"}
:::

:::Changelog{title="27.08.2020"}
::ChangelogItem{type="added" description="licenses can now be ordered by customer reference"}
:::

:::Changelog{title="21.08.2020"}
::ChangelogItem{type="added" description="added Product endpoints to swagger"}

::ChangelogItem{type="added" description="exposed Devices GET to be used with management api key"}

::ChangelogItem{type="fixed" description="Replace &#x22;short code&#x22; with &#x22;product code&#x22;"}
:::

:::Changelog{title="20.08.2020"}
::ChangelogItem{type="improved" description="Add basic search filters to Product List"}
:::

:::Changelog{title="19.08.2020"}
::ChangelogItem{type="improved" description="Better search UI on product, customer, license and order lists"}
:::

:::Changelog{title="12.08.2020"}
::ChangelogItem{type="improved" description="Filtering licenses by product name"}

::ChangelogItem{type="improved" description="Added search field to product list - Search by name, Search by product code"}

::ChangelogItem{type="fixed" description="Correct status in response when updating license"}

::ChangelogItem{type="fixed" description="Exporting orders over management API"}
:::

:::Changelog{title="v3.57.0 (10.8.2020.)"}
::ChangelogItem{type="fixed" description="Include consumption_period when creating orders"}

::ChangelogItem{type="fixed" description="Disabled user is left as NULL when disabling licenses over management API"}

::ChangelogItem{type="added" description="added new issue license multi step form"}

::ChangelogItem{type="added" description="company preferences expanded with company name change field"}
:::

:::Changelog{title="v3.56.0 (28.7.2020.)"}
::ChangelogItem{type="fixed" description="Fix 'Set password' CSS alignment"}
:::

:::Changelog{title="v3.52.0"}
::ChangelogItem{type="fixed" description="Various fixes to Stripe handling"}

::ChangelogItem{type="fixed" description="Allow deleting orders"}
:::

:::Changelog{title="3.45.0"}
::ChangelogItem{type="improved" description="Private Network Floating Licences Added to the Enterprise tier"}

::ChangelogItem{type="improved" description="Added new validation - max simultaneous users number cannot be higher than max activations"}

::ChangelogItem{type="improved" description="Show total value inside subscription form in Billing configuration view"}

::ChangelogItem{type="improved" description="Activation features limited to max 5 on standard pricing plan"}

::ChangelogItem{type="improved" description="Added billing data edit feature to standard accounts: plan_type (only when in trial), coupon and tax_rate"}

::ChangelogItem{type="improved" description="Added scheduled update feature to billing configuration"}

::ChangelogItem{type="improved" description="Added Offline floating license to product and licenses (is_floating)"}

::ChangelogItem{type="fixed" description="CheckProductNumber takes only non-archived products in to the count"}

::ChangelogItem{type="fixed" description="Fixed setting validity period on license edit"}

::ChangelogItem{type="fixed" description="Product features format for issuing license uses code instead of feature_id"}
:::

:::Changelog{title="10.6.2020"}
::ChangelogItem{type="improved" description="Fixed documentation link inside 'SDK Integration' tab on Product page"}

::ChangelogItem{type="fixed" description="On License page added a link to that license customer page"}

::ChangelogItem{type="improved" description="Changed message text for existing license user warning popup to &#x22;Do you want to assign the license to existing user?&#x22;"}

::ChangelogItem{type="improved" description="On license list table placed &#x22;Times activated&#x22; and &#x22;Max activations&#x22; columns side by side"}

::ChangelogItem{type="added" description="Added scrollbar on top instead of on the bottom of the overflowed tables"}

::ChangelogItem{type="added" description="Added copy button to the Order and License page title (to copy license key, license user or order id)"}

::ChangelogItem{type="added" description="&#x22;Maintenance period&#x22; column title changed to &#x22;Maintenance End Date&#x22;"}

::ChangelogItem{type="improved" description="Changed customer name cell formatting (last name, first name)"}

::ChangelogItem{type="added" description="Added &#x22;Search by the first name&#x22;, &#x22;Search by the last name&#x22; and &#x22;Search by phone number&#x22; search types to the Customers list page"}

::ChangelogItem{type="added" description="Added &#x22;Search by customer name&#x22; search type to the Order and License list pages"}

::ChangelogItem{type="added" description="Added license count, order count, customer count and products count to dashboard"}

::ChangelogItem{type="added" description="Added table rows per page option form license and order list (added to UI options)"}
:::

:::Changelog{title="16.4.2020"}
::ChangelogItem{type="added" description="Added: address, postcode, city, country, state fields on Customer model. Support in webhook/order and platform"}
:::

:::Changelog{title="3.14.0"}
::ChangelogItem{type="added" description="Added product delete (archive) and order delete capabilities"}
:::

:::Changelog{title="26.2.2020."}
::ChangelogItem{type="added" description="Platform app (frontend)"}

::ChangelogItem{type="added" description="Changed UI layouts preferences saving model (options: column display, column sort); now preferences are saved for a specific user and not the whole company"}

::ChangelogItem{type="added" description="Added the Prevent virtual machine flag to the app."}

::ChangelogItem{type="added" description="Implemented a self-serve platform"}

::ChangelogItem{type="added" description="Registration, plan type, billing, automatic Stripe integration"}

::ChangelogItem{type="improved" description="Improved UI&#xA;"}

::ChangelogItem{type="added" description="Custom prompt messages"}

::ChangelogItem{type="improved" description="Better error handling"}

::ChangelogItem{type="added" description="Platform backend"}

::ChangelogItem{type="added" description="Added plan types for companies and features based on plan types handling"}

::ChangelogItem{type="added" description="Implemented trial and inactivity logic for companies"}

::ChangelogItem{type="added" description="Implemented checking and handling company’s Stripe subscriptions"}
:::

:::Changelog{title="v2.2.21"}
::ChangelogItem{type="added" description="editing custom field on a license"}
:::

:::Changelog{title="8.11.2019."}
::ChangelogItem{type="fixed" description="editing license"}

::ChangelogItem{type="added" description="User-based product licensing"}

::ChangelogItem{type="added" description="Company code now editable on the company - a requirement for User-based licensing."}
:::

:::Changelog{title="23.10.2019."}
::ChangelogItem{type="improved" description="Implemented consumption features for a product"}

::ChangelogItem{type="fixed" description="Fixes to user-based licensing"}
:::

:::Changelog{title="10.10.2019."}
::ChangelogItem{type="fixed" description="maintenance period not updating after disabling maintenance"}

::ChangelogItem{type="added" description="Added persistent sort on license list"}

::ChangelogItem{type="added" description="Added editing of customer email"}
:::

:::Changelog{title="26.9.2019."}
::ChangelogItem{type="fixed" description="sorting on orders and licenses"}

::ChangelogItem{type="fixed" description="searching of licenses by user email"}

::ChangelogItem{type="added" description="Tweaked select component"}

::ChangelogItem{type="improved" description="Changed sort of customer by last name instead of first name"}
:::

:::Changelog{title="20.9.2019."}
::ChangelogItem{type="added" description="Implemented custom sort for licenses on license_key/customer field in the license list"}

::ChangelogItem{type="fixed" description="Fixed sorting of orders by customer email on order list"}

::ChangelogItem{type="fixed" description="Fixed product detail period row showing on non-periodic license types in product detail view"}

::ChangelogItem{type="fixed" description="Fixed sorting in order list by customer_email instead of the customer.email field"}

::ChangelogItem{type="added" description="Added hostname and IP fields to device details"}

::ChangelogItem{type="added" description="Added device custom variables"}
:::

:::Changelog{title="26.8.2019."}
::ChangelogItem{type="added" description="&#xA;Added License and Device.last_check, timestamp of last license check for a given license"}

::ChangelogItem{type="added" description="Added Device.app_ver"}
:::

:::Changelog{title="23.8.2019."}
::ChangelogItem{type="fixed" description="&#xA;sorting licenses by Status"}

::ChangelogItem{type="added" description="devices listed for each License. Resetting an individual device license"}

::ChangelogItem{type="added" description="export orders to CSV"}

::ChangelogItem{type="added" description="custom columns settings"}

::ChangelogItem{type="added" description="custom fields on a license/product"}
:::

:::Changelog{title="19.8.2019."}
::ChangelogItem{type="fixed" description="sorting licenses by Status"}

::ChangelogItem{type="added" description="devices listed for each License. Resetting an individual device license."}
:::

:::Changelog{title="30.7.2019."}
::ChangelogItem{type="added" description="license users initial"}
:::

:::Changelog{title="19.7.2019."}
::ChangelogItem{type="added" description="export orders to CSV"}
:::

:::Changelog{title="10.7.2019."}
::ChangelogItem{type="added" description="custom columns settings"}

::ChangelogItem{type="added" description="initial version of custom fields"}
:::

:::Changelog{title="23.5.2019."}
::ChangelogItem{type="added" description="offline licensing portal released"}
:::

:::Changelog{title="21.5.2019."}
::ChangelogItem{type="added" description="Resetting trial licenses fixed"}

::ChangelogItem{type="fixed" description="After activating perpetual licenses (non-trial), the Expiration Date is set to the date it is created."}

::ChangelogItem{type="fixed" description="When issuing a license with order ID set to &#x22;a&#x22;, our dashboard just says &#x22;Error&#x22;"}

::ChangelogItem{type="fixed" description="What does the &#x22;reset&#x22; function in the dashboard do? Just reset the license activation state? For example, it doesn't reset the trial period in the case of a trial license."}

::ChangelogItem{type="fixed" description="Fixed creating manual orders with trial licenses"}
:::

:::Changelog{title="7.5.2019."}
::ChangelogItem{type="added" description="License model"}

::ChangelogItem{type="improved" description="Removed null=true from total_consumptions"}
:::

:::Changelog{title="7.5.2019."}
::ChangelogItem{type="added" description="License model"}

::ChangelogItem{type="improved" description="Removed null=true from total_consumptions"}
:::

:::Changelog{title="26.4.2019."}
::ChangelogItem{type="fixed" description="Fixed bug where you could not access specific order or license through a deep link. The resolution was to change URL structure of app(added companyId in URL)"}

::ChangelogItem{type="added" description=" IE9+ support"}

::ChangelogItem{type="added" description="company settings page under account/settings"}

::ChangelogItem{type="added" description="platform version"}

::ChangelogItem{type="added" description="staff dashboard page with the company list"}

::ChangelogItem{type="added" description="form to create a new company through platform within platform version"}

::ChangelogItem{type="fixed" description="user consent bug"}

::ChangelogItem{type="fixed" description="issue with customer data not being stored when creating an order from platform"}

::ChangelogItem{type="added" description="consumption licenses behaving properly"}
:::

:::Changelog{title="26.4.2019."}
::ChangelogItem{type="fixed" description="Fixed bug where you could not access specific order or license through a deep link. The resolution was to change URL structure of app(added companyId in URL)"}

::ChangelogItem{type="added" description=" IE9+ support"}

::ChangelogItem{type="added" description="company settings page under account/settings"}

::ChangelogItem{type="added" description="platform version"}

::ChangelogItem{type="added" description="staff dashboard page with the company list"}

::ChangelogItem{type="added" description="form to create a new company through platform within platform version"}

::ChangelogItem{type="fixed" description="user consent bug"}

::ChangelogItem{type="fixed" description="issue with customer data not being stored when creating an order from platform"}

::ChangelogItem{type="added" description="consumption licenses behaving properly"}
:::

:::Changelog{title="6.3.2019."}
::ChangelogItem{type="fixed" description="Fixed returning resources for staff users"}

::ChangelogItem{type="added" description="ProductFeature model"}

::ChangelogItem{type="added" description="product_feature ManyToMany on License"}

::ChangelogItem{type="added" description="product_feature on Product"}

::ChangelogItem{type="improved" description="Modified sentry for staging and production only"}

::ChangelogItem{type="improved" description="Removed /accounts/registration/* except /account-confirm-email"}

::ChangelogItem{type="improved" description="Removed /api/v1/rest-auth/* except /password/change"}
:::

:::Changelog{title="26.2.2019."}
::ChangelogItem{type="added" description="License.date_expires - date when the license expires"}

::ChangelogItem{type="added" description="License.license_type - determining the type of this exact license (subscription, perpetual, time-limited...)"}
:::

:::Changelog{title="16.1.2019."}
::ChangelogItem{type="improved" description="Removed LicenseType, including from migrations."}
:::

:::Changelog{title="15.1.2019."}
::ChangelogItem{type="improved" description="ProductUpgrade deprecate"}

::ChangelogItem{type="added" description="upgrade_from to Product"}

::ChangelogItem{type="added" description="Updates to handling upgrades - see LicenseSpring.md"}
:::

:::Changelog{title="11.1.2019."}
::ChangelogItem{type="added" description="LicenseType model"}

::ChangelogItem{type="added" description="license_types on Company, Product"}

::ChangelogItem{type="improved" description="License to use LicenseType - it is still a string (PK), so it kinda didn't change :)"}

::ChangelogItem{type="added" description="license_types on a Product are supposed to be a subset of Company.license_types"}

::ChangelogItem{type="improved" description="removed license_model on Product (replaced by license_types)"}
:::

v3.208.0

[title] Subscription Integration
[path] Integrations/

## Webhooks



::::Tabs
:::Tab{title="Event-Driven Notifications"}
- Webhooks are automated messages sent from apps when something happens.


:::

:::Tab{title="Real-Time Updates"}
- They allow you to receive real-time updates about events in other services
- Webhook setup for subscription licenses
:::
::::

## Webhooks Workflow Inside App

**Trigger Event:&#x20;**&#x57;hen the specified event occurs in the third-party service, it makes an HTTP request to the webhook URL you provided(E.g Client buys a Subscription product)

**Payload Processing:&#x20;**&#x59;our server then receives this request, parses the payload, and takes any necessary actions

## **LicenseSpring Implementation**

### a) New Subscription

When user buys a subscription product this action will trigger event of webhook which will send **Payload** to you&#x72;**&#x20;server/application** and [**create order**](https://docs.licensespring.com/management-api/order/create-order) (license of **subscription type** with **validity period**).

### b)  Subscription Update

When user extend subscription successfully this will trigger event that subscription charge was successful which will [**update license**](https://docs.licensespring.com/management-api/license/update) expiration date.

### c) Subscription Cancel

When webhook triggers subscription cancel event you should [**deactivate license**](https://docs.licensespring.com/license-api/activation-deactivation/deactivation).&#x20;

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/t9TNPsgjxA326_1xji5gz_image.png)

## Integrations for LicenseSpring

Our platform now offers  integrations with a variety of third-party services

- [**FastSpring**](https://docs.licensespring.com/integrations/fastspring)
- [**Stripe**](https://docs.licensespring.com/integrations/stripe)
- [**Salesforce**](https://docs.licensespring.com/integrations/salesforce)
- [**Shopify**](https://docs.licensespring.com/integrations/shopify)

****


[title] Floating Server V2
[path] Floating Server/

**LicenseSpring's Floating Server v2&#x20;**&#x69;s a comprehensive upgrade delivering a modern, scalable, and future-ready evolution of our on-premises licensing server. With significant advancements across its architecture, API, and operational capabilities, the second iteration of the LicenseSpring Floating Server offers enhanced reliability, and a consistent developer experience across the LicenseSpring ecosystem.

The Floating Server v2 is a complete rewrite of our existing on-premise server solution. This version introduces a modernised architecture and a rewritten codebase, aiming to meet the growing demands of performance, maintainability, and cross-product alignment.

## Key Enhancements and Objectives

1\. Go SDK-Powered Core

At the heart of Floating Server v2 lies the LicenseSpring Go SDK, responsible for:

- Direct communication with the LicenseSpring Cloud
- Full support for license lifecycle operations (activation, deactivation, consumption, etc.)
- Unified hardware ID algorithm with all of LicenseSpring's supported SDKs.
- Data model parity between the Floating Server and the LicenseSpring Cloud
- Standardised implementation patterns with the wider LicenseSpring product suite

### 2. Streamlined Deployment and Configuration

Deployment and configuration workflows have been redesigned for simplicity and scalability:

- Support for credential provisioning per server instance via the LicenseSpring platform
- Secure, signed communication between server instances and SDKs
- Improved platform UI visibility to monitor all deployed floating servers

### 3. Enhanced Storage and Sync Flexibility

Floating Server v2 will introduce:

- Transition from Redis to a robust relational database backend
- Configurable storage options (e.g., SQLite, PostgreSQL) via a settings file
- Expanded options for data synchronisation:
  - Periodic sync
  - On-demand sync
  - Full online and offline modes

### 4. User Interface redesign

The server management UI will be reimplemented using React, aligning with the Vendor Portal's design system for a cohesive user experience.

### 5. Enhanced API Documentation

All API endpoints will include integrated **Swagger** documentation, ensuring clearer developer guidance and streamlined integration.



## Additional Features and roadmap

In the future, LicenseSpring has plans to extend the Floating Server v2's capabilities to further meet our customer's requirements :

### Multi-Vendor Support

Floating Server v2 will support shared server instances across multiple vendors, enabling flexible and collaborative licensing infrastructures.

### Advanced Reporting and Analytics

Gain deeper insights with improved analytics and reporting tools, providing actionable data across all server activities.


[title] Vendor Platform SSO
[path] Common Scenarios/Single Sign On (SSO)/

The LicenseSpring Vendor Platform supports Single Sign-On (SSO) to allow internal users— such as administrators, developers, and support teams — to securely access the management dashboard using their organization's identity provider (IdP). By integrating SSO, vendors can enforce centralized authentication policies and streamline access control across their team.

This section provides a step-by-step guide to configure SSO within the Vendor Platform. The process includes registering your SSO provider, configuring SAML or OIDC settings, and verifying the connection. Once enabled, users will be able to authenticate via your IdP using their organizational credentials.

## Setup Single Sign On

To configure Single Sign-On (SSO) for your organization, you must first navigate to the appropriate section within the LicenseSpring Vendor Platform. This is where you can add and manage your identity provider (IdP) settings.

Follow the steps below to access the SSO configuration view:

1. **Log in to the Vendor Platform**
   - Go to [**https://saas.licensespring.com**](https://saas.licensespring.com) and sign in with your admin credentials.
2. **Navigate to Organization Settings**
   - From the sidebar menu, click on **“Settings”**.
   - This section contains configuration options that apply across your entire LicenseSpring account, including access control.
3. **Select the “SSO Settings” Tab**
   - Within the Settings view, select the **“SSO Settings”** tab.
   - This view allows you to add a new SSO provider , and view current authentication settings.
4. **Click “Add  Provider”**
   - To begin the integration process, click on the **“Add SSO Provider”** button.
   - You will be prompted to enter details based on your IdP’s protocol (SAML or OIDC).

:::hint{type="warning"}
If you do not see the “SSO Settings” tab, ensure that you have the necessary admin privileges or contact your LicenseSpring account manager.
:::

![](https://archbee-image-uploads.s3.amazonaws.com/U9x6bSuQrpDmdgq5PGwu3-4pfuh163e9HEYO9hFyMiA-20250418-131226.png)

Depending on your selected Identity Provider, you will have to submit following informations:

- `Name` and `.xml provider metadata file` for SAML providers.
- `Name`, `Client ID` and `Client secret` for Google identity provider.
- `Service ID`, `Key ID`, `Team ID` and` .p8 key file` for Apple identity provider.

:::hint{type="info"}
Check `Create new platform user if it does not exist already` if you want to allow all users from your identity provider to login to the LicenseSpring platform. In that case for every new logged in user, LicenseSpring will create a new vendor application user for your account.
:::

Instructions on how to register your application to acquire required informations are described below.

### **Extracting the Company Code**

You will need Company code to succesfully register your application in your identity provider dashboard. To find your company code, follow the next steps:

- Inside LicenseSpring vendor platform navigate to **Settings--> Preferences**&#x20;
- Pay attention to the **Company code** field. In this case Company code is **DSE2**



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/3syMEq4bbwIlNOMnOIREn_image.png "Company code")

## Integrating Social Identity Providers

Before setting up a social IdP, it's necessary to register your application with the respective IdP to acquire a client ID and client secret.

### Google

1. [**Create a developer account with Google**](https://developers.google.com/identity) if you haven't already.
2. Access the [**OAuth consent screen page**](https://console.cloud.google.com/apis/credentials/consent).
3. Opt for the `external` User Type and proceed to create it.
4. Provide `app information`, `app domain` (optional), and `developer contact details`.
5. Save and move forward.
6. Configure Scopes:
   - Include Scopes like `.../auth/userinfo.email`, `.../auth/userinfo.profile`, `openid`.
7. Update settings and save.
8. Continue to Test users settings and save.
9. Navigate to the [**Credentials page**](https://console.cloud.google.com/apis/credentials).
10. `Create credentials` > `OAuth client ID`.
11. Select `web application` type, name your OAuth 2.0 client.
12. `Add URIs` to authorized JavaScript origins and authorized redirect URIs.&#xA;**&#x20;Authorized JavaScript origins:&#x20;**[**https://auth.licensespring.com&#xA;**](http://auth.licensespring.com)**Authorized redirect URIs:&#x20;**[**https://auth.licensespring.com/realms/platform/broker/\{COMPANY\_CODE}/endpoint**](https://auth.licensespring.com/realms/platform/broker/\{COMPANY_CODE}}/endpoint)
13. Create and note down your `Client ID` and your `Client Secret`.
14. Go back to `Add SSO Provider` form in the LicenseSpring vendor platform and finish the setup.

### Apple

1. **Go to the Apple Developer Console**: Visit [**Apple Developer Console**](https://developer.apple.com/account/).
2. **Create an Apple Developer Account**:
   - If you don't have an Apple Developer account, you will need to create one and enroll in the Apple Developer Program.
3. **Create a New App ID**:
   - Navigate to "Certificates, Identifiers & Profiles".
   - Under Identifiers, click the "+" button to create a new App ID.
   - Choose "App IDs" and click "Continue".
   - Enter a description and a bundle ID (e.g., keycloak)
   - Under "Capabilities", enable "Sign in with Apple".
   - Click "Continue" and then "Register".
4. **Create a Service ID**:
   - Still under "Identifiers", click the "+" button to create a new Service ID.
   - Select "Service IDs" and click "Continue".
   - Enter a description and an identifier (e.g., **keycloak-service**)
   - Click "Continue" and then "Register".
   - After creating the Service ID, click on it to edit it.
   - Enable "Sign in with Apple" and configure the redirect URI:
     [**https://auth.lcensespring.com/realms/platfrom/broker/\{COMPANY\_CODE}/endpoint**](https://auth.licensespring.com/realms/platform/broker/\{COMPANY_CODE}/endpoint)
   - Add the primary App ID created earlier as the Primary App ID.
   - Click "Save".
5. **Create a Key for Apple Sign-In**:
   - Navigate to "Keys" and click the "+" button to create a new key.
   - Enable "Sign in with Apple" and click "Configure".
   - Select the Primary App ID and click "Save".
   - Click "Continue" and then "Register".
   - Download the key file it will have a .p8 extension) and save it securely. You will not be able to download it again.
6. **Get Your Team ID and Key ID**:
7. Note down your **Team ID** from your Apple Developer account.
8. Note down the **Key ID** from the key details.
9. Note down service identifier as mentioned before ins step 4. : **keycloak-service**
10. Have your **key file** ready to upload it on platform.
11. Go back to `Add SSO Provider` form in the LicenseSpring vendor platform and finish the setup.

## Incorporating SAML Identity Providers

To enable SAML IdP sign-in for your app users:

- Follow your SAML identity provider's instructions to add a relying party or application for your SAML 2.0 IdP.
- Configure the assertion consumer endpoint in your SAML identity provider to:
- `https://auth.licensespring.com/realms/platform/broker/{COMPANY_CODE}/endpoint`
- **Existing configs with legacy prefixed (DO NOT USE FOR NEW CONFIGS):** `https://{_domain_name_}.auth.{_region_}.amazoncognito.com/saml2/idpresponse`
- Some SAML IdPs might require the SP urn / Audience URI / SP Entity ID:
  - Use `https://auth.licensespring.com/realms/platform`
  - **Existing configs with legacy prefixed (DO NOT USE FOR NEW CONFIGS):&#x20;**`urn:amazon:cognito:sp:{_user_pool_id}`
- Configure your SAML IdP to provide an email value (claim) in the SAML assertion.
- Support SAML 2.0 federation with post-binding endpoints. This ensures direct receipt of SAML responses via a user agent, eliminating the need for retrieval and parsing.
- Go back to `Add SSO Provider` form in the LicenseSpring vendor platform and finish the setup.

### Microsoft Entra (formerly Azure Active Directory)

**Setup steps:**

1. Access [**Azure Portal**](https://portal.azure.com/) and choose Azure Active Directory.
2. `Add` an `enterprise application`.
3. Create your own application, input `name`, and select `non-gallery` option.
4. Opt for `single sign-on` > `SAML`.
5. Edit Basic SAML Configuration:
   - Set Identifier as` https://auth.licensespring.com/realms/platform`
   - **Existing configs with legacy prefixed (DO NOT USE FOR NEW CONFIGS):&#x20;**`urn:amazon:cognito:sp:{_user_pool_id_}`
   - Configure Reply URL as `https://auth.licensespring.com/realms/platform/broker/{COMPANY_CODE}/endpoint`
   - **Existing configs with legacy prefixed (DO NOT USE FOR NEW CONFIGS):&#x20;**`https://{_domain_name_}.auth.{_region_}.amazoncognito.com/saml2/idpresponse`
6. Save and close the settings.
7. Download Federation Metadata XML.
8. Go back to `Add SSO Provider` form in the LicenseSpring vendor platform and finish the setup.

**Instrucitons to allow SP Initiated Login:**

1. On the LicenseSpring SSO integration (enterprise application) -> Properties -> Set "Visible to users?" to No
2. Create a new enterprise application,  input `name`, and select `non-gallery` option.
3. Under Single sign-on select `Linked`
4. Set the `Sign on URL` to `https://auth.licensespring.com/realms/platform/protocol/openid-connect/auth?client_id=platform&redirect_uri=https%3A%2F%2Fsaas.licensespring.com&response_type=code&scope=openid&kc_idp_hint={COMAPNY_CODE}`

:::hint{type="danger"}
**Error:&#x20;**&#x41; common Azure DB provider SSO error is shown in the screenshot below:
:::

![Azure DB Common Error.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/lsPoyx3AW21xEQ4g-ePvK_image.png "User not assigned to a role for application.")

To resolve this error, follow these steps:

1. In the [**Azure Active Directory Admin Center**](https://aad.portal.azure.com/#blade/Microsoft_AAD_IAM/StartboardApplicationsMenuBlade/AllApps/menuId/AllApps), select your app and then search for and select the application to which you want to assign the user account.
2. In the left pane select Users and Groups and then select Add User/Group.

![Assign Users/Groups](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/5pRSGqAjymqw9Y9I0kVO4_image.png "Assign Users/Groups")

![Select Add User/Group](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ave65WsXKA1-bvkpTimgs_image.png "Select Add User/Group")

&#x20;   3\. On the Add Assignment pane, select None Selected under Users and Groups
&#x20;   4\. Search for and select the user that you want to assign to the application, select Select
&#x20;   5\. On the Add Assignment, select Assign at the bottom of the pane
&#x20;   6\. When all steps are completed, user can normally sign in to account using SSO

![Final step to assign user to application](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/HE4yf2apy8uxYIh3AHUca_image.png "Final step to assign user to application")

### Auth0

**Create an Auth0 Application**

1. Access the Auth0 website dashboard.
2. Click on Applications, then select Create Application.
3. In the Create Application dialog box, provide a name for your application (e.g., My App).
4. Choose Single Page Web Applications as the application type.
5. Click the Create button.

**Create a Test User**

1. Navigate to the left navigation bar and select User Management.
2. Click on Users.
3. Choose + Create Your First User. Alternatively, if this is not your initial user, select + Create User.
4. Within the Create user dialog box, input the user's email and password.
5. Click the Save button.

**Configure SAML Settings**

- Access the left navigation bar and click on Applications.
- Select the name of the application you previously created.
- Go to the Addons tab.
- Activate the SAML2 Web App option.
- Within the Addon: SAML2 Web App dialog box, navigate to the Settings tab.
- For the Application Callback URL, input [`https://auth.licensespring.com/realms/platform/broker/{COMPANY_CODE}/endpoint`](https://auth.licensespring.com/realms/platform/broker/\{COMPANY_CODE}/endpoint)``
  - Please substitute company code with the appropriate value from platform for your **company\_code,&#x20;**&#x75;nder platform settings.
  - **Existing configs with legacy prefixed (DO NOT USE FOR NEW CONFIGS):&#x20;**`https://_domain_name_.auth._region_.amazoncognito.com/saml2/idpresponse`
- Under Settings, input the following:
  - `{`
    `  "mappings": {`
    `    "user_id": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",`
    `    "email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",`
    `    "given_name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",`
    `    "family_name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"`
    `  },`
    `  "nameIdentifierFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",`
    `  "nameIdentifierProbes": [`
    `    "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"`
    `  ]`
    `}`
  - Replace \_user\_pool\_id\_ with the value from your SSO settings.
  - **Existing configs with legacy prefixed (DO NOT USE FOR NEW CONFIGS):&#x20;**&#xA;`{`
    `   "audience": "urn:amazon:cognito:sp:_user_pool_id_",`
    `   "mappings": {`
    `     "email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"`
    `   },`
    `   "nameIdentifierFormat": "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"`
    ` }`
- (Optional) Choose Debug, then log in as the test user you created to confirm that the configuration works.
- Choose Enable, and then choose Save.

**Get the IdP Metadata**

1. In the Addon: SAML2 Web App dialog box, on the Usage tab, find Identity Provider Metadata. Then do either of the following:
2. Choose download to download the .xml metadata file.
3. Go back to `Add SSO Provider` form in the LicenseSpring vendor platform and finish the setup.

### Okta

**Create a SAML App**

1. Open the Okta Developer Console.
2. In the navigation menu, expand Applications, and then choose Applications.
3. Choose Create App Integration.
4. In the Create a new app integration menu, choose SAML 2.0 as the Sign-in method.
5. Choose Next.

**Configure SAML Integration**

1. On the Create SAML Integration page, under General Settings, enter a name for your app.
2. Choose Next.
3. Under GENERAL, for Single sign on URL, enter [`https://auth.licensespring.com/realms/platform/broker/{COMPANY_CODE}/endpoint`](https://auth.licensespring.com/realms/platform/broker/\{COMPANY_CODE}/endpoint)
   - **Existing configs with legacy prefixed (DO NOT USE FOR NEW CONFIGS):&#x20;**`https://{domain_name}.auth.{region}.amazoncognito.com/saml2/idpresponse`
4. For Audience URI (SP Entity ID), enter [**https://auth.licensespring.com/realms/platform/broker/\{COMPANY\_CODE}/endpoint**](https://auth.licensespring.com/realms/platform/broker/\{COMPANY_CODE}/endpoint)``
   - **Existing configs with legacy prefixed (DO NOT USE FOR NEW CONFIGS):&#x20;**`urn:amazon:cognito:sp:{user_pool_id}`
5. Under ATTRIBUTE STATEMENTS (OPTIONAL), add a statement with the following information:
   - For Name, enter the SAML attribute name `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`
   - For Value, enter `user.email`.
6. For all other settings on the page, leave them as their default values or set them according to your preferences.
7. Choose Next.
8. Choose a feedback response for Okta Support.
9. Choose Finish.

**Assign a User**

1. On the Assignments tab for your Okta app, for Assign, choose Assign to People.
2. Choose Assign next to the user that you want to assign. Note: If this is a new account, the only option available is to choose yourself (the admin) as the user.
3. (Optional) For User Name, enter a user name, or leave it as the user's email address, if you want.
4. Choose Save and Go Back. Your user is assigned.
5. Choose Done.

**Get the IdP Metadata**

1. On the Sign On tab for your Okta app, find the Identity Provider metadata hyperlink.&#x20;
2. Right-click the hyperlink, and then copy the URL.&#x20;
   - If not found then click View SAML setup instructions and save the value from Provide the following IDP metadata to your SP provider into an xml file.
3. Go back to `Add SSO Provider` form in the LicenseSpring vendor platform and finish the setup.

**SP Initiated login**

In order to use the Okta dashboard to access LicenseSpring apps directly some changes are needed to the standard setup mentioned below:

1. Under GENERAL, for Single sign on URL, use: `https://auth.licensespring.com/realms/platform/broker/{COMPANY_CODE}/endpoint/clients/platform-saml`
2. Uncheck "Use this for Recipient URL and Destination URL
3. For Recipient URL, use:
   `https://auth.licensespring.com/realms/platform/broker/{COMPANY_CODE}/endpoint`
4. For Destination URL use:&#x20;
   `https://auth.licensespring.com/realms/platform/broker/{COMPANY_CODE}/endpoint/clients/platform-saml`
5. For Audience URI (SP Entity ID), use:&#x20;
   `https://auth.licensespring.com/realms/platform/broker/{COMPANY_CODE}/endpoint/clients/platform-saml`

## OpenID Connect (OIDC) Integration

LicenseSpring Platform supports Single Sign-On (SSO) via **OpenID Connect (OIDC)**.
&#x20;Customers may integrate any identity provider that supports the standard Authorization Code Flow, including:

- **Azure Active Directory (Entra ID)**&#x20;
- **Okta**&#x20;
- **Auth0**&#x20;
- **Google Identity**&#x20;

This feature allows organizations to authenticate their users using their own identity system, while LicenseSpring handles user provisioning and access control.

### OIDC Redirect URI

Every OIDC provider must be configured to redirect authentication responses to the following URL:

[**https://auth.licensespring.com/realms/platform/broker/\{company\_code}/endpoint**](https://auth.licensespring.com/realms/platform/broker/\{company_code}/endpoint)

Replac&#x65;**&#x20;\{company\_code}** with the company code assigned to your organization in LicenseSpring.
This redirect URI **must match exactly** in your identity provider configuration.

## Google Identity (OIDC)

### Steps for Google

1. Go to [**https://console.cloud.google.com**](https://console.cloud.google.com)
2. APIs & Services → Credentials&#x20;
3. Create Credentials → OAuth client ID&#x20;
4. Application type: **Web Application**&#x20;

- Authorized JavaScript origins:

:::BlockQuote{listStyleType="disc" listStart="2" indent="1"}
[**https://auth.licensespring.com**](https://auth.licensespring.com/)
:::

- Add Authorized redirect URI:&#x20;

:::BlockQuote{listStyleType="disc" listStart="4" indent="1"}
[**https://auth.licensespring.com/realms/platform/broker/\{company\_code}/endpoint**](https://auth.licensespring.com/realms/platform/broker/\{company_code}/endpoint)
:::

6. Create&#x20;
7. Copy:&#x20;

- Client ID&#x20;
- Client Secret&#x20;

8. Ensure OAuth Consent Screen is configured and published

### Metadata URL

[**https://accounts.google.com/.well-known/openid-configuration**](https://accounts.google.com/.well-known/openid-configuration)




![Origins and redirect URIs](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ZGXXQZxO7-py_JB_eBIOY_image.png "Origins and redirect URIs")

## Microsoft Azure AD (Entra ID)

### Steps in Azure

1. Sign in to Azure Portal: [**https://portal.azure.com**](https://portal.azure.com)
2. Go to **Microsoft Entra ID → App registrations → New registration**
3. **Important note:** we create **App registrations**, not Enterprise Application&#x20;
4. Enter a name (e.g., LicenseSpring OIDC)&#x20;
5. Supported account types: **Accounts in this organizational directory only**&#x20;
6. Add Redirect URI (Web): [**https://auth.licensespring.com/realms/platform/broker/\{company\_code}/endpoint**](https://auth.licensespring.com/realms/platform/broker/\{company_code}/endpoint)
7. Click **Register**&#x20;
8. Copy **Application (client) ID**&#x20;
9. Copy **Directory (tenant) ID**&#x20;
10. Go to **Certificates & secrets → New client secret**&#x20;
11. Copy generated **Client Secret Value**&#x20;
12. Go to **Authentication**, confirm redirect URI is present&#x20;
13. (Optional) Assign users/groups to the application

### Metadata URL

:::BlockQuote
[**https://login.microsoftonline.com/\{tenant\_id}/v2.0/.well-known/openid-configuration**](https://login.microsoftonline.com/\{tenant_id}/v2.0/.well-known/openid-configuration)
:::

Azure will autofill:

- Authorization URL&#x20;
- Token URL&#x20;
- JWKS&#x20;
- Issuer

## Okta (OIDC)

### Steps in Okta

1. Log in to Okta Admin&#x20;
2. Go to **Applications → Create App Integration**&#x20;
3. Sign-in method: **OIDC**&#x20;
4. Application type: **Web Application**&#x20;
5. Add Sign-in redirect URI: [**https://auth.licensespring.com/realms/platform/broker/\{company\_code}/endpoint**](https://auth.licensespring.com/realms/platform/broker/\{company_code}/endpoint)
6. Sign-out redirect URI optional&#x20;
7. Assign application to users/groups&#x20;
8. Copy:&#x20;
   - Okta domain&#x20;
   - Client ID&#x20;
   - Client Secret

### Metadata URL

:::BlockQuote
https\://\{okta\_domain}/oauth2/default/.well-known/openid-configuration
:::

domain example:

:::BlockQuote
[**https://dev-12345678.okta.com**](https://dev-12345678.okta.com)
:::

## Auth0 (OIDC)

### Steps in Auth0

1. Log in: [**https://manage.auth0.com**](https://manage.auth0.com)
2. Go to **Applications → Applications → Create Application**&#x20;
3. Choose **Regular Web Application**&#x20;
4. Go to **Settings**&#x20;
5. Add to Allowed Callback URLs: [**https://auth.licensespring.com/realms/platform/broker/\{company\_code}/endpoint**](https://auth.licensespring.com/realms/platform/broker/\{company_code}/endpoint)&#x20;
6. Add same value to Allowed Logout URLs (optional)&#x20;
7. Copy:&#x20;
   - Domain&#x20;
   - Client ID&#x20;
   - Client Secret&#x20;
8. Save changes&#x20;

### Metadata URL

:::BlockQuote
https\://\{tenant}.auth0.com/.well-known/openid-configuration
:::

Example of tenant:
[**https://dev-123abc45.auth0.com**](https://dev-123abc45.auth0.com)

Add callback URL:

:::BlockQuote
[**https://auth.licensespring.com/realms/platform/broker/\{company\_code}/endpoint**](https://auth.licensespring.com/realms/platform/broker/\{company_code}/endpoint)
:::

## Required OIDC Information

All required metadata is in well known openid configuration which you can import, or you can fill it manually.

## Configuration Steps on platform


Navigate to
&#x20;**Platform → Settings → Single Sign-On**&#x20;

1. Click **Add SSO Provider**&#x20;
2. Select **OpenID Connect (OIDC)**&#x20;
3. Enter the required fields (Client ID, Client Secret, import well known configuration or rarely do it manual)&#x20;
4. Enable (recommended):
   &#x20;**✓ Create new platform user if it does not exist**&#x20;
5. Save the configuration&#x20;
6. Use the SSO login on your next signin

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/mv_lpw7gMmWgaxkIjdJo2_image.png)


Login Using Single Sign On
--------------------------

Once you have succesfully added your on identity provider to the LicenseSpring vendor platform SSO settings, you can continue logging in to the platform.

Return to the LicenseSpring login page and locate and click on **Change login method**, the&#x6E;**&#x20;SSO**.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/IlAx4-WhD_1dG_zuJHcCY_image.png "Login method")

- A prompt will ask for the company code. Here, enter you&#x72;**&#x20;Company code** extracted in the previous steps.&#x20;

![SSO login](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8ahzSuPm0aeyfu7QRZ393_image.png "SSO Login")

If you have added the provider correctly and there were not errors during configuration step, you should be logged in to your company account.

If you require assistance or have custom SSO requirements, please contact [**LicenseSpring Support**](https://licensespring.zendesk.com/agent/).

[title] FastSpring Contextual Store
[path] Integrations/FastSpring/

This guide will go over some of the most common scenarios for which FastSpring will integrate with LicenseSpring.

:::hint{type="info"}
This Guide will work both for products and subscriptions that are configured at key-based or user-based on LicenseSpring. There are additional sections at the bottom of this guide for specific use-cases
:::

:::hint{type="info"}
For subscriptions, it's the same integration as for products below, with a few small precisions added at the bottom of this guide.
:::

Follow these steps to configure licensing for products that you sell in FastSpring:

1. Activate FastSpring integration in LicenseSpring
2. Setup Product Attributes
3. Setup License Generation
4. Setup webhook integration

## 1. Activate FastSpring integration in LicenseSpring

Go to Settings > Integrations > FastSpring and click **Activate**

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Xbn0SiUg3zqu9vY5hbzlI_screenshot-2023-11-08-at-135156.png)

Select the **Management API key** and **License API key** (also known as **uuid**, this is the key that will later be used in webhook integration setup)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/wh1Krecw8rh24WpwPSYV5_screenshot-2023-11-08-at-132740.png)

## 2. Setup Product Attributes

1. Go to FastSpring "Products" section
2. Open your product.
3. In the Options > "Custom attributes" dialog of your product

- `uuid` - **required**, can be found in your LicenseSpring account under Settings > Keys > License API keys
- `product_short_code` - **required**, with the code you configured LicenseSpring product with
- `max_activations`  - optional, INT. If this field is not included, the default from the product configuration in Licensespring will be used.
- `floating_cloud` - optional, INT. If this value is set licenses from this product will be created as floating cloud. This value also sets the total number of machines / users that can concurrently use a floating cloud license ( Max simultaneous license users value in LicenseSpring configuration ). Needs to be less than or equal to max activations attribute value.
- `floating_users_from_quantity` - optional, BOOL. Quantity is used to determine max simultaneous license users instead of max\_activations on single floating cloud licenses. See [**FastSpring Contextual Store**](docId\:oA87A_qPwFbVL73NTklxf)
- `license_type` - optional, STRING. If this field is not included, the default license type from the product configuration in LicenseSpring is used (`perpetual`, `time-limited`, `subscription`, `consumption`). For subscription products license type is always subscription.
- `valid_duration` - optional, STRING. If this field is not included, the default valid\_duration from the product configuration in LicenseSpring is used. The format for this is `N[d/w/m/y]` where N is number and option between d,w,m,y is possible (day, week, month, year). **Not applicable for subscription licenses.&#x20;**&#x50;lease see the section about Subscriptions for instructions on configuring a subscription.
- `maintenance_duration`- optional, STRING behaves same as the `valid_duration` field
- `max_consumptions` - optional, INT, will be applied on non subscriptions only, when license type attribute is set to `consumption`
- `enable_maintenance_duration`- optional, turns on maintenance capability. If not defined, default from LS is used
- `is_license_manager` - optional, sets customer as a license manager. Useful on license-key or user-based products where the customer is not set as a license manager by default.
- `assign_customer_as_user` - optional, BOOL, customer will be automatically assigned to the license as a license user. Can be added only for products with **user authorization method**
- `grace_period`- optional, INT, sets grace period ( in hours ) for the subscription license.
- `user_max_activations` - optional, INT. To change the `max_activations` for a customer **assigned** to a license **as a license user**, use this attribute along with the `assign_customer_as_user` attribute. If this field is not included, the default is 1. Can be added only for products that use the **user authorization method**.
- `ignore_product_in_licensespring` - optional, BOOL. When set to `true`, incoming webhooks for the specified product will be ignored, and a `200` status code will be returned to FastSpring as a response.
- `disable_licenses_only_on_full_refund` - optional, BOOL. When set to `true`, only licenses that are fully refunded will be disabled. Licenses will remain enabled in the case of partial refunds.
- `is_trial` - optional, BOOL. When set to `true`, licenses are created as trial licenses. Applicable only for non-subscription licenses. To customize the trial days duration, override the `trial_days` value on the corresponding license policy.
- `dynamic_max_activations` - optional, BOOL. When set to `true`, the `max_activations` value is calculated dynamically as the product **quantity** multiplied by the `user_max_activations` defined in the selected license policy (the default license policy is used if none is specified). This attribute can only be used with **user-based** products, requires the `assign_customer_as_user` attribute, and applies only when the license type is set to **single license**.

### **License policy**

For every product in the LicenseSpring platform you can define one or many license policies which act as a template when creating licenses. License policy can be added to the FastSpring products as a custom attribute key **license\_policy** with value of some license policy code. When order is being created via FastSpring, our integration will take all the fields, product features and custom fields from included license policy and create the license based on those.

- `license_policy` - If **license\_policy** is defined, then instead of using separate features, FastSpring looks at the **license\_policy** code, and sets features on a license based on the features that are added to the license\_policy in LicenseSpring

:::hint{type="warning"}
The **license\_policy** attribute and the features, as described here, can't both be used inside the same product configuration

For example, if you decide to use the **license\_policy&#x20;**&#x61;ttribute then you can't be using features, and vice versa, if you decide to use **features&#x20;**&#x74;hen you need to remove the **license\_policy&#x20;**&#x61;ttribute.
:::

### **Custom fields**

[**Custom fields**](https://docs.licensespring.com/docs/custom-fields) can be also customized using FastSpring. **After custom fields have been created on the LicenseSpring product with some default value** we can customize them using custom attributes.

If we have for example some custom field named `Serial` with default value `111` and we want to create a custom value for this field on some license we would add this custom attribute key to the FastSpring product in format `custom_field_{valueName}`:

ex. key **custom\_field\_Serial** and add some value to it.

Note that for every custom field which we would want to customize we need to add separate custom attribute in the above mentioned format `custom_field_{valueName}`.

:::hint{type="info"}
Please note that you need to do this for *every&#x20;*&#x70;roduct you plan to process through LicenseSpring.
:::

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/WpS83cQUh6_k3XBJWXSbO_image.png "Opening \"Custom attributes\" in FastSpring")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/_3DYqXk9fcdFrrF0EfZzz_attrs.png)

:::hint{type="info"}
If the number of fields isn't enough, save all the attributes that you can and after that reopen the window, then more fields should appear.
:::

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Xey2NNus3nmu2etqTNCi-_screenshot-2023-07-31-at-144734.png "Retrieving uuid and mgmt key")

## 3. Set-up License Generation

:::hint{type="info"}
If your product is key based, you need to add a license generation fulfillment to the FastSpring product. This will generate a license key during order create process.

This is not needed for the user based products.
:::

1. In the "Products section, open your product
2. in the "Fulfillment" section, click "ADD FULFILLMENT"
3. Select "Generate a License" as action and "Remote Server Request" as Generator.
4. Press NEXT to come to configuration
5. Set the following settings in the dialog:
   - URL: [`https://integrations.licensespring.com/api/generate_license`](https://integrations.licensespring.com/api/generate_license)
   - Method : `HTTP POST`
   - POST Encoding:` UTF-8`
   - Output format : `Single line license (Quantity based)`

![](https://kwiki-user-media.s3.amazonaws.com/staging/content/image_widgets/remote_server_request.png "License generation fulfillment")

##

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/PdetPH5-0P2W8u5p0nvIt_screenshot-2024-02-12-at-095845.png)

### Customizing the License Character Set

To customize the set of characters used when generating licenses, follow these steps:

1. Navigate to the **Product** where your license fulfillment is configured.
2. Under the **Fulfillments** section, locate the fulfillment configuration you previously set up and click **Edit**.
3. On the **Remote License Configuration** page, click on the **Parameters** tab.
4. Add a new parameter with the following details:
   - **Name**: alphabet
   - **Value**: The set of characters you want to use for license generation (e.g., ABCDEFG1234567).

Once this parameter is added, the license generator will use your specified character set for all licenses issued through this fulfillment.

Examples are provided in the two images below.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/w4McozlTceQ4zJg4J-m2F_screenshot-2025-07-28-at-160011.png)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/_-UQ36AlD1XL2_f555DFd_screenshot-2025-07-28-at-154549.png)

## 4. Set-up webhook integration

These are events we identified as important and currently support:

1. In your FastSpring store, go to "Integrations" and then "Webhooks"
2. First, add a new webhook section with the "ADD WEBHOOK" button in upper right.
   - The title can be anything you like, but we recommend something relating to LicenseSpring.
   - **You must enable "Enable webhook expansion"**
3. In the new webhook section, add a new webhook by pressing "ADD WEBHOOK URL" and fill it out with:

`url`: `https://integrations.licensespring.com/api/fastspring` `HMAC SHA256 Secret`: Enter the "Shared key" from your LicenseSpring Account. You can find this under "Account Settings > Settings > Keys" \`In the list of events below, the following events:

- `order.completed` - **Required** for **all** license types.
- `return.created` - licenses will be **disabled** if the order is refunded

For subscriptions, please also send the following webhooks:

- `subscription.deactivated`
- `subscription.canceled`
- `subscription.uncanceled`
- `subscription.updated`
- `subscription.payment.reminder`
- `subscription.payment.overdue`
- `subscription.charge.completed`
- `subscription.charge.failed`
- `subscription.paused`
- `subscription.resumed`

:::hint{type="info"}
Information on Fastspring's webooks can be found [**here.**](https://fastspring.com/docs/webhooks/)&#x20;

Only the **order.completed&#x20;**&#x65;vent is needed if you are not using subscriptions
:::

![](https://kwiki-user-media.s3.amazonaws.com/staging/content/image_widgets/add_webhook_2_CGlHsXb.png "Add a title to your new webhook and be sure to enable webhook expansion")

![](https://kwiki-user-media.s3.amazonaws.com/staging/content/image_widgets/add_webhook_3.png "Add Webhook URL Endpoint")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/eKeDG0bPTuiKsl5tOALam_screenshot-2023-11-08-at-145612.png)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/RAem0vjnS5Z63zr6K4GIJ_screenshot-2023-07-31-at-145554.png "Select the appropriate events to send back to LicenseSpring")

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/S4rpsIJW3ofIyGx1ZLq8K_screenshot-2023-07-31-at-145327.png "You can find your Shared Key in your LicenseSpring Account")

:::hint{type="info"}
All webhook events from FastSpring are stored as "License history" and available in the platform as a "history log" for each license. This history log can be found under the "Usage report" for a license.
:::

![](https://kwiki-user-media.s3.amazonaws.com/staging/content/image_widgets/License_usage_report.png "FastSpring Webhook events will be found under a license's \"Usage report\" on LicenseSpring")

## Webhook Events

This section describes what the expected behavior is for the webhooks.

**order.completed**

This is the main webhook, and is triggered after clearing payment and all fulfilment actions.

- In LicenseSpring: Creates an order and Licenses.
- **Subscriptions**: A Subscription-type license is automatically put into active state and the validity\_period will match the billing period set on FastSpring

The other events pertain to Subscription Handling:

**subscription.deactivated**

Is triggered after cancellation at the end of the remaining period, or when "deactivate now" option is used in FastSpring.

- In LicenseSpring: This event will deactivate all associated licenses and devices immediately

**subscription.canceled**

Is triggered when the subscription is cancelled will be deactivated on next payment period.

- In LicenseSpring: The event is logged to the license history, but has no effect on the status of the license. It is expected that subscription.deactivated will trigger properly.

**subscription.uncanceled**

Is triggered when cancelling a subscription is reverted.

- In LicenseSpring: The event is logged to the license history, but has no effect on the status of the license.

**subscription.updated**

Is triggered after a manual/API update of subscription.

- In LicenseSpring: Updates the license based on `active` and `next` parameters. Others ignored. For single licenses updates change in quantity (max\_activations) and ads `End Date` to a license note

**subscription.payment.reminder**

Notification

- In LicenseSpring: The event is logged to the license history, but has no effect on the status of the license.

**subscription.payment.overdue**

Notification

- In LicenseSpring: The event is logged to the license history, but has no effect on the status of the license.

**subscription.charge.completed**

Is triggered when subscription is renewed (it is NOT triggered for a new subscription).

- In LicenseSpring: Updates "Expiration date" (validity\_period) to match next value of webhook payload.

**subscription.charge.failed**

Notification

- In LicenseSpring: The event is logged to the license history, but has no effect on the status of the license.

**subscription.paused**

Is triggered after the subscription is paused at the end of the remaining period.

- In LicenseSpring: This event will disable all associated licenses immediately

**subscription.resumed**

Is triggered when a subscription is resumed (The subscription had to be paused beforehand).

- In LicenseSpring: This event will enable again all associated licenses.

**return.created**

Is triggered when an order is refunded.

- In LicenseSpring: This event will disable all associated licenses

## More information on specific scenarios

### User-Based Licenses:

The Customer email address is assigned as a "license manager" role and he is supposed to assign licenses in the [**User Portal**](https://users.licensespring.com/), or email(s) of end-users should be provided in the webhook request.

### Subscription trials:

Subscriptions can be set with some free trial days when editing subscription price. When order is created using subscription with trial days, LicenseSpring integration will recognize this and create trial license using sent trial days. Expiration date will be set using FastSpring event data.

On first **subscription.charge.completed** event this license will be changed from trial to full license.

![](https://kwiki-user-media.s3.amazonaws.com/staging/content/image_widgets/Screen_Shot_2021-03-24_at_12.45.51_PM.png "Edit subscription pricing")

### Subscriptions - Configuration Notes:

Instead of going to the Products tab, you go to the Subscriptions tab, and after that, the setup is the same as it is for products. ( Choose a price and set the necessary custom attributes )

### Single license for multiple quantities or multiple users

In your store, user can select different quantities for a product. Default behaviour is that multiple quantities will result in **multiple licenses** (both user and license-key based!).

If instead, when user selects >1 quantity you want to make a SINGLE license that can be activated multiple times (for license-key based) or a SINGLE license that supports multiple users (for user-based licenses), you need to:

For license-key based, in license fulfilment settings change:

1. On product fulfilment add an additional parameter `single_license`and set its value to`true`, here are the steps:
   1. In "Catalog" select the desired product
   2. On the product page scroll down to the fulfilment section
   3. Click on the "Edit" button on the desired fulfilment
   4. On the edit page click on the "Parameters" tab
   5. Add the `single_license` parameter and set its value to`true`
2. Additionally add `single_license` custom attribute to the product and set it's value to `true` to ensure subscription updates will work as expected.
   1. In "Catalog" select the desired product
   2. In the upper right corner in the dropdown select the "Custom Attributes"
   3. Add `single_license` custom attribute and set it's value to `true` (image below)
   4. Click the "save" button on the custom attribute pop up window
   5.

![](https://kwiki-user-media.s3.amazonaws.com/staging/content/image_widgets/single_license.png "Setting single-license behaviours")

### Max simultaneous license users from quantity on a single license

In case of single floating-cloud license, quantity can be used to determine max simultaneous license users instead of max\_activations for license-key based or number of users for user based products. To enable this, please use this following combination of custom attributes on the product:

- `floating_users_from_quantity` : `true`
- `floating_cloud` : `1`
- `max_activations` - optional, INT. If this field is not included, the default from the product configuration in Licensespring will be used.

:::hint{type="warning"}
Also, the products fulfillment **needs** to be set as described in the single license section shown above.
:::

### Issue different license types for the same product

In LicenseSpring, a product can issue perpetual, time-limited, consumption, and subscription licenses. FastSpring only allows their products to be configured as either perpetual or subscriptions. To create a time-limited license, for instance, you need to add following custom attribute on product:

`license_type` = time-limited

Just like in Subscriptions example, you can use the same Product Configured in LicenseSpring for many different products in FastSpring.

### Features

You can add features to both products and to subscriptions. Features need to be first set up as a normal product in FastSpring. The name does not matter. However, the custom attribute is what is used to recognize which feature to add to a license. You therefore need to set a custom attribute with the following:

`feature_code` = my\_feature (where my\_feature is for example code of the feature on a product).

No additional configuration is required (such as fulfilment)

:::hint{type="info"}
The product path and feature code need to be the same so our Licensespring \<> FastSpring integration can properly update the features when subscription is updated.
:::

![Add the feature code from LicenseSpring as a custom attribute in FastSpring](https://kwiki-user-media.s3.amazonaws.com/staging/content/image_widgets/feature_1.png "Add the feature code from LicenseSpring as a custom attribute in FastSpring")

On the main product, add the feature as a "Related offer". Select *Add Product options* inside the `Add new` selector.

![Add Related Offers to the main product](https://kwiki-user-media.s3.amazonaws.com/staging/content/image_widgets/features_2_LxS5E1J.png "Add Related Offers to the main product")

![Add features to the main product in the main popup](https://kwiki-user-media.s3.amazonaws.com/staging/content/image_widgets/feature_4.png "Add features to the main product in the main popup")

### Product Bundles

Product bundle is a unique type of product in LicenseSpring that requires specific configuration. This section outlines all the currently available **Product Attributes** for product bundles and instructions on how to use them.

:::hint{type="warning"}
Only **one** product bundle can be processed per order. Multiple quantities of the same product bundle **are supported**; however, including two or more **different** product bundles in the **same order** on FastSpring is **not** supported.
:::

**How to set up product bundles in LicenseSpring?**

1. Go to the **Products** section in LicenseSpring platform
2. Click the **Add new bundle** button

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/wTUy6_ZK7-I06p4PDQYRS_image.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/wTUy6_ZK7-I06p4PDQYRS_image.png" size="100" caption isUploading="false" width="2988" height="724" darkWidth="2988" darkHeight="724" indent="2"}

3. Insert the desired **Bundle name&#x20;**&#x61;nd **Bundle code**, choose which **Authorization method to use**, and finally, select all the products that you want inside the bundle

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/XJbs1DPEaNQpUQupP0Bti_image.png" signedSrc size="60" width="898" height="1032" position="center" caption darkWidth="898" darkHeight="1032" indent="2"}

4. After the bundle is created, it should look something like the following picture. Take the **Bundle code** value and use it as the **product\_short\_code** in the FastSpring configuration. (Look at the list below to see all the available **Product attributes** for **bundle products**)

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/H3BatFY8_bd8mVVZk6D49_image.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/H3BatFY8_bd8mVVZk6D49_image.png" size="100" caption isUploading="false" width="2464" height="1050" darkWidth="2464" darkHeight="1050" indent="2"}



:::hint{type="info"}
All other setup steps are the same as they are for basic Products. The only difference is in the supported **Product attributes**.
:::

:::hint{type="info"}
If a product bundle contains, for example, three products, then four licenses will be created in LicenseSpring. One license will be for the bundle itself, which can be used for all products within the bundle. The remaining three licenses will be created for each individual product in the bundle. The value of these individual licenses is determined by the **default license policy of each product**.
:::

:::hint{type="warning"}
Features (in FastSpring) are **not** supported. Each license will include the features defined in the **default license policy** of the product for which the license was created.
:::



**Product Attributes**

1. Go to FastSpring "Products" section
2. Open your product
3. In the Options > "Custom attributes" dialog of your product

- `uuid`- **required**, can be found in your LicenseSpring account under Settings > Keys > License API keys
- `is_product_bundle` - **required**, BOOLEAN, has to be set to `true`
- `product_short_code` - **required**, with the code you configured LicenseSpring Product **Bundle** with
- `max_activations`  - optional, INT. If this field is not included, the value from the default license policy on the product in Licensespring will be used.
- `floating_cloud` - optional, INT. If this value is set licenses from this product bundle will be created as floating cloud. This value also sets the total number of machines / users that can concurrently use a floating cloud license ( Max simultaneous license users value in LicenseSpring configuration ). Needs to be **less than or equal** to max activations attribute value.
- `floating_users_from_quantity` - optional, BOOL. Quantity is used to determine max simultaneous license users instead of max\_activations on single floating cloud licenses. See [**FastSpring Contextual Store**](docId\:oA87A_qPwFbVL73NTklxf)
- `license_type` - optional, STRING. If this field is not included, the default license type of each product inside the bundle configuration in LicenseSpring is used (`perpetual`, `time-limited`, `subscription`, `consumption`). For subscription products license type is always **subscription**.
- `valid_duration` - optional, STRING. If this field is not included, the default valid\_duration of each product inside the bundle configuration in LicenseSpring is used. The format for this is `N[d/w/m/y]` where N is number and option between d,w,m,y is possible (day, week, month, year). **Applicable** for `time-limited` licenses **only**.
- `maintenance_duration`- optional, STRING behaves same as the `valid_duration` field
- `max_consumptions` - optional, INT, will be applied on non subscriptions only, when license type attribute is set to `consumption`
- `enable_maintenance_duration`- optional, turns on maintenance capability. If not defined, default from LS is used
- `is_license_manager` - optional, sets customer as a license manager. Useful on license-key or user-based products where the customer is not set as a license manager by default.
- `assign_customer_as_user` - optional, BOOL, customer will be automatically assigned to the license as a license user. Can be added only for products with **user authorization method**
- `grace_period`- optional, INT, sets grace period ( in hours ) for the subscription licenses.
- `user_max_activations` - optional, INT. To change the `max_activations` for a customer **assigned** to a license **as a license user**, use this attribute along with the `assign_customer_as_user` attribute. If this field is not included, the default is 1. Can be added only for products that use the **user authorization method**.
- `ignore_product_in_licensespring` - optional, BOOL. When set to `true`, incoming webhooks for the specified product will be ignored, and a `200` status code will be returned to FastSpring as a response.
- `disable_licenses_only_on_full_refund` - optional, BOOL. When set to `true`, only licenses that are fully refunded will be disabled. Licenses will remain enabled in the case of partial refunds.

### Product bundle license policies

You can define a specific license policy for each individual product within a bundle.

1. Go to FastSpring "Products" section
2. Open your product
3. In the Options > "Custom attributes" dialog of your product

To override the default license policy for a product in the bundle:

- Use the **product short code** as the attribute **key**.
- Use the **license policy short code** as the attribute **value**.

Example

If you have a bundle containing 3 products and want to override the license policy for the second product:

- Assume the second product’s short code is `short_code_prod_2`
- Assume the license policy you want to apply is `license_policy_2`

Then, in the **Custom Attributes**:

- **Key**: `short_code_prod_2`
- **Value**: `license_policy_2`



:::hint{type="warning"}
FastSpring requires that the **key attribute** in custom attributes is at least **3 characters long**. If your product short code is shorter than that, you can add a prefix to meet this requirement.

Use the following format: **product\_in\_bundle\_**\{product\_short\_code}

**Example**

For a product short code of **AB**, the required custom attribute key is **product\_in\_bundle\_AB**. If the license policy short code is **lp2**, the resulting key–value pair is:

Key: **product\_in\_bundle\_AB**
Value: **lp2**
:::


[title] Running & Administration
[path] Floating Server/Floating Server V2/

## Starting the Server

Once your configuration file is ready, you can start the Floating Server in one of the following ways:

### Method 1: Executable

If you are using the executable, run the binary matching your operating system:

:::BlockQuote
./floating-server
:::

### Method 2: Docker

1. **Pull the image&#x20;**
2. docker pull licensespring/floating-server-v2\:v2.0.0-beta.`1`
3. **Set up PostgreSQL**
   - Start a PostgreSQL instance (local or containerized).
   - Note the` host`,` port`, `username`,` password`, and `database` name.
   - Update your configuration file with these details.
4. **Prepare configuration and certificates**
   - Place the configuration file in a local directory.
   - Place certificates in another directory.
5. **Run the container**
   Mount both the configuration and certificate directories so that the container has access:

:::BlockQuote
docker run -d  &#x20;
\--name fsv2 \\&#x20;
\--network fsnet \\
-v /path/to/config:/app/config&#x20;
-v /path/to/certs\:/app/certs&#x20;
-p 8080:8080 \\
licensespring/floating-server-v2\:v2.0.0-beta.1
:::

:::hint{type="success"}
- **Replace&#x20;**/path/to/config with your config directory.
- **Replace** /path/to/certs with your certificates directory.
- **Adjust&#x20;**-p if exposing on a different port.
:::

### Method 3: Docker Compose

A prebuilt **docker-compose.yml&#x20;**&#x69;s included in the documentation. Running it sets up both PostgreSQL and the Floating Server in one step:

:::BlockQuote
docker-compose up -d
:::

This is the fastest way to get everything running.

## First-Time Admin Setup

When the server starts for the first time, no users or admins exist. You must set the initial **admin password**.

:::hint{type="info"}
- Default username: **admin**
- **Password:** defined during setup.
:::

### Setting the Password

You can set it via:

**1. UI:&#x20;**&#x4E;avigate to the Floating Server’s URL. You’ll be redirected to the password setup page.

![](https://archbee-image-uploads.s3.amazonaws.com/6CLcmIv1QNNDgKDDEXj7l-sidn6wAKJjd6RBOYzC6Hf-20250808-015307.png "Running the Floating Server for the first time: Setting initial Admin Password")

**2. API** : Call the endpoint:

:::BlockQuote
POST /api/v5/auth/initial-password
:::

### Logging In

Once the initial password is set:

- Log in using admin and your chosen password.
- You will then access the Floating Server admin panel.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/4HXLLr5Q7QtA2dEoLTkx7_image.png "Image of the Floating Server Running")

- From here, you can create additional user accounts.

:::hint{type="info"}
After starting the server:

- **Executable:** A log file is generated automatically.&#x20;
- **Docker:** Use docker logs to view server output.
:::




[title] Common scenarios
[path] /




[title] FAQ
[path] Floating Server/

### What Does “Max Activations” Field Mean in Terms of Floating Licenses?

When you install floating licenses on the Floating server, Max activations field determines on how many servers you are able to install that same license on.

### How Do I Control Which Device Is Allowed to Connect to the Floating Server?

Floating server is designed to be deployed in a secure internal network (e.g. with VPN). Therefore, each user should be a trusted user. If you still want to authenticate users, you can setup an authentication proxy for Floating server.

### When Configuring Licenses for Floating Server, Why Do I Need to Enter Both Product and License Key?

Floating server can be configured with multiple licenses at the same time. Setting the product allows us to determine to which product that license corresponds to.

### Configured Floating Server With One License. How Do I Add a Different License for the Same Product?

In **Floating Server Version 1** of our platform, it is not possible to add multiple licenses for the same product. To change a license, you must first remove the existing license before adding a new one. However, in **Floating Server Version 2**, you can add multiple licenses for the same product, allowing greater flexibility in managing your deployments..

### Floating Server Requires API and Shared Keys. Is It Safe to Share Them With My Customers?

Those keys only give you access to the License API, and not to the Management API. License API is a very limited subset of LicenseSpring API, so it is safe to share those keys.

### Can the on-prem server run headless (command-line only, no UI)?

Yes, the on-prem server can be run headless. After deployment using any of the available options, you can communicate with the server through command-line scripts. These scripts can be generated using our tool at LicenseSpring API Documentation. Every server functionality can be executed with corresponding command-line arguments.

### How does the on-prem license server node-lock to the system?

When a license is activated through the on-prem server, the server uses the machine identifier of the operating system to generate a unique hardware ID, binding the license to that specific system. In Docker setups, the machine ID is derived from the host machine’s ID, and the license is tied to this hardware ID for future operations.

### Is there a better implementation for node-locking in Docker setups on systems without internet access?

Yes, node-locking in Docker containers can be effectively implemented if the Docker volumes remain secure and unmodified. Our recommendation is to secure the Redis instance’s Docker volume, as it plays a key role in the node-locking mechanism.

For systems without internet access, we provide offline or air-gapped licenses, which do not require internet connectivity. Alternatively, Physical Hardware Keys (dongles) can be used to enforce node-locking, requiring their presence for license validation.

### Can VM detection handle WSL detection from inside a WSL Linux instance?

No, currently, our floating server does not support detection of WSL (Windows Subsystem for Linux) instances.

### How is the hardware ID determined by default?

The hardware ID is generated using the machine identifier from the underlying operating system or host machine. This unique ID is used to bind licenses to the system where the floating server is running.

### How can I prevent server cloning when using the executable in air-gapped or virtualized deployments?

To protect against server cloning, the hardware ID is used to tie the server to a specific machine. LicenseSpring also supports Yubikey 5 hardware-based security for additional protection. If your environment doesn't allow external hardware (such as in fully virtualized systems), it's recommended to use expiration dates on licenses as an alternative safeguard. LicenseSpring is exploring software-only server cloning prevention protocols that may be available in the future.

### Is the floating license server's database (Badger-DB) running as a separate process in the executable method?

No, the Badger-DB database is integrated directly into the floating server executable (floating-server.exe). There is no separate process to manage. The database runs within the executable, making it easier to monitor and control without extra overhead.

### **How can I check if my license is still valid?&#x20;**

Retrieve the license validity status through the SDK or License API by checking the`is_expired` field.[**&#x20;License Check**](https://app.archbee.com/docs/FbT_Z5Cu33D-LVZx1fRkU/Zh4KFIh_s59TzIBZKeb9o)

[title] Add license
[path] Floating Server/Floating Server V1/API Reference/license/

{
  "id": "FzDghPnbKFVC3pPUqLJa3",
  "data": {
    "url": "http://localhost:8080/api/v4/addProduct",
    "name": "Add license",
    "method": "GET",
    "request": {
      "pathParameters": [],
      "queryParameters": [
        {
          "kind": "required",
          "name": "product",
          "type": "string"
        },
        {
          "kind": "optional",
          "name": "licenseKey",
          "type": "string"
        },
        {
          "kind": "optional",
          "name": "username",
          "type": "string"
        },
        {
          "kind": "optional",
          "name": "password",
          "type": "string"
        }
      ],
      "headerParameters": [],
      "bodyDataParameters": [],
      "formDataParameters": []
    },
    "responses": [
      {
        "statusCode": "200",
        "description": "",
        "jsonExample": ""
      }
    ],
    "contentType": "application/json"
  },
  "type": "api-oas-v2",
  "children": [
    {
      "text": ""
    }
  ]
}
[title] SalesForce Integration Installation Tutorial
[path] Integrations/Salesforce/

## Introduction and Prerequisites

This article is a tutorial on the necessary steps that you need to take to install our LicenseSpring SalesForce integration on your SaleForce instance.

We are assuming that you have a **SalesForce** **instance&#x20;**&#x61;nd &#x61;**&#x20;LicenseSpring instance** setup beforehand and that you have the **admin rights** needed to install applications on it and edit / add **Lightning Record Pages.**

## App Installation

The integration is a SalesForce app that can be installed by using the following link:

[**https://login.salesforce.com/packaging/installPackage.apexp?p0=04tgK0000009PwrQAE**](https://login.salesforce.com/packaging/installPackage.apexp?p0=04tgK0000009PwrQAE)

:::hint{type="info"}
The App is currently not published on the SalesForce marketpace, but we are planning to do so in the future so users will be able to find the app on the SalesForce marketpalce as well.
:::

Once you **click** on the **link** and log into you **SaleForce instance** you will be show the following page in the image below:

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/b-gYZLJr-1cUDlo9A1cmt_screenshot-2024-10-29-at-121704.png)

In this page you have the ability to pick who will be able to use the app in your SF instance (the choice does not matter from the perspective of the integration so choose which ever you prefer for your use case).

After you choose the permission setting, you will need to check the check mark "*I acknowledge that I'm isntalling a Non - Salesforce Applicaiton*"  and then click on the "**Install"** button.

This will take you to a loading animation.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/30DLbaUIJJ1l_LVRWDhDS_screenshot-2024-10-29-at-121744.png)

If everything is installed correctly you will be show the following message: "**Installation Complete!".**

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/hJHyCioPlLCe2GWTffJ8d_screenshot-2024-10-29-at-121829.png)

## Lightning Pages Setup

Now the application is installed and we need to add the applications UI to the **Contacts** and **Accounts** **Record pages** so that we are able to see and use our integration on those Lightining Pages.

:::hint{type="warning"}
Our integration currently supports the the **Contacts** and **Accounts** SalesForce objects.&#x20;

The integraiton only works in the SalesForce **record** pages. You are able to add the integraton to any Lightning page types, but it wont work properly.

If you need the integration to work with other SF **objects** or on other **Lightning page types** please submit a a **support ticket&#x20;**&#x74;o our support team: [**https://licensespring.zendesk.com/hc/en-us/requests/new**](https://licensespring.zendesk.com/hc/en-us/requests/new)
:::

Go to the **setup** page.

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/pWy7BRM-BqV3eTK1qKELu_screenshot-2024-10-29-at-123731.png" signedSrc size="38" width="450" height="482" position="center" caption darkWidth="450" darkHeight="482"}

On the setup page, click on to th&#x65;**&#x20;Lightning App Builder.**

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/VTkrjx0Xw-oTmuMBGPAFg_screenshot-2024-10-29-at-124012.png)

:::hint{type="info"}
There may already be Lightning pages listed in your SalesForce instance.
:::



Click on the "New" button if you do not already have &#x61;**&#x20;Lightning record page** for the **contact** and **account** objects.

:::hint{type="warning"}
If you do have a **Lightning record page&#x20;**&#x66;or the **contact** and **account** objects, you will need to click on the **edit** button on those **pages.&#x20;**&#x54;his will take you to the Lightning Page editing tool, so you can skip the next few steps of the tutorial by clicking on this link on the right Side of the screen for the "Lightining Page editing tool / Lightning App Builder"
:::

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/QlP-FOl2a07ZEehagkdW8_screenshot-2024-10-30-at-093952.png)

In the above step, click "**Record Page**" and click the "**Next**" button.

You will be prompted to create a **label** and pick an **object** for the Page.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/du3W3c3ASRj77V8s154hS_screenshot-2024-10-30-at-100625.png)

For the **label** you can put anything you like, but make sure it is **recognizable&#x20;**(in our case we will put "ContactRecordPage"), and for the **Object** you need to pick "**contact**"

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/uROg8bnSfg5vWnwKeSbMn_screenshot-2024-10-30-at-100855.png" signedSrc size="64" width="1004" height="732" position="center" caption darkWidth="1004" darkHeight="732"}

After you click next, you will need to pick a **tempalate**, or clone an existing page. Choose what ever is the best for your use case and click "**Done**"

### Lightining Page editing tool / Lightning App Builder

Once that is done, you will be redirected to the **editing tool&#x20;**&#x66;or the newly created **Lightning Page** (or an existing page)**.**

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Zrz9hVzhViWL8_fnL7fXS_screenshot-2024-10-30-at-102251.png)

:::hint{type="info"}
If in the steps above you have picked to edit an already existing contact or account record page, you would be redirected to this editing tool.
:::

On this step you will add the LicenseSpring integrations UI component to the Page.

You can do so by scrolling to the bottom of the component list on the left side of the screen, or by searching for the "**contactLicensesPreview**" component.

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Cw2tHZtKrikGdmOICAVOX_screenshot-2024-10-30-at-102205.png" signedSrc size="38" width="586" height="236" position="center" caption darkWidth="586" darkHeight="236"}

To add the component, you will need to drag and drop the **contactLicensesPreview component** to an empty slot on the page where you wish for our integrations UI to be shown later on.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/MPWtC3xLYWzS_OnjgItNd_screenshot-2024-10-30-at-103817.png)

In the example, we have also added the "Record detail" component just to have more informaiton on the page.

When our component is added, click **'Save',&#x20;**&#x61;nd click **'Activation...'**.

This will take us to the Activation wizard. On this wizard you have additional options on how to show / use the page. You decide on how / where you want to show the page. For this example, we will click on **Assign as Org Default&#x20;**&#x61;nd after a couple of more custom options that you can choose based on your use case you are done with the integration setup for the **contact** object.

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/I9y82vHDEhZJIC18hmtfv_screenshot-2024-10-30-at-121039.png" signedSrc size="82" width="1930" height="1298" position="center" caption darkWidth="1930" darkHeight="1298"}

Repeat the steps on the **account** object and it&#x73;**&#x20;Lightning page.&#x20;**

1. Go to the **Lightning App builder.**
2. Add a new Account Record page or edit an existing one.
3. Add our **accountLicensesPreview.**
4. Save the page and activate it.

### Management Api Key

Now when we have **installed** the app and added the needed component to our **pages** we can go to any **contact** or **account** record and we should be able to see the integration window.&#x20;

To do so we need to go back to the SalesForce home page, click on the upper lef&#x74;**&#x20;9 dots&#x20;**&#x69;con, and search for **Contacts** or **Accounts.**

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ODRtz9wDrn3ZLCEL5MlhU_screenshot-2024-10-30-at-122712.png)

The last step in the integration setup is for us to set the **LicenseSpring Management API key.**

To do so, log into the [**LicenseSpring Vendor Platform**](https://saas.licensespring.com)**,**&#x63;lick on the **settings** and click on the "**Keys**" tab.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/FxUdgUXAUyfR4tlMwZS2n_screenshot-2024-10-30-at-123003.png)

On this tab, we need to copy our Management API key that is **active** and is **not read only.**

Now go back to your SalesForce instance and paste the key in the text field "Management Api Key" and click on the **"Set Key"** button in the lower right corner of the integration window (image below showing the field in which to paste the key).

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Ylfzvrz2OfZBZzW0i0ERn_screenshot-2026-01-13-at-105455.png)

:::hint{type="warning"}
If users who are not system administrators are going to use the integration, they must be assigned the **LS\_Admin&#x20;**&#x70;ermission set. In addition, they need the standard object permission **User External Credential&#x20;**&#x67;ranted. This permission cannot be assigned through the installed package and must be granted manually, as explained [**here**](https://help.salesforce.com/s/articleView?id=ind.fsc_admin_enable_user_access_to_user_external_credentials_object.htm\&type=5).
:::

## Additional Steps for Single-Tenant Instances

If you are using a single-tenant instance, you’ll need to update the Named Credential URL to point to your dedicated **integrations** instance. Go to Setup → Named Credentials, locate the **LS credential**, click Edit, and update the URL accordingly.

By default, the URL is [**https://integrations.licensespring.com**](https://integrations.licensespring.com), but your instance will have its own integrations endpoint so you'll need to use that endpoint. If you are not sure what endpoint you are using, contact our support team, and they will help you find it

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/4bNujOxI2mXhxuWyGnbD4_image.png)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8L2jFHBFDedq8dEQ4aleb_image.png)

## Contact Support

If you still have issues with the setup, need answers to certain questions or need additional functionalities added to the integration, feel free to contact our LicenseSpring support team: [**https://licensespring.zendesk.com/hc/en-us/requests/new**](https://licensespring.zendesk.com/hc/en-us/requests/new)






[title] Multiple license users on the same device
[path] Common Scenarios/

## Overview

When using **user-based** licenses, a user should be assigned per device due to limitations in our database model. For scenarios involving multiple users sharing devices, we recommend using a naming convention for HWIDs — for example, adding a suffix/prefix like `station_hwid_user1`. When a user operates locally, they can override the HWID with something like `local_hwid_user1`. When user has `max_activations = 1 `this will lead to user using either `station_hwid_user1` or `local_hwid_user1`. This ensures that each HWID is uniquely associated with a single license user, preventing conflicts when multiple users (with different emails) are using the same machine. The current flow is flawed because it relies on the hardware ID as the source of truth instead of the license user, which can lead to incorrect activation tracking and conflicts across shared devices.If your business logic uses hardware\_id for additional check up be sure to add suffix/prefix always.&#x20;

## Platform

Create a user based license and assign license users to the license.&#x20;

![](https://t4573966.p.clickup-attachments.com/t4573966/a4896459-7eb9-402c-8791-1d8ce9397a75/Screenshot%202025-06-09%20at%2009.10.03.png)

## SDK flow

To support hardware ID overwrites, the system must use the `HardwareID` algorithm in combination with the username. In this example, we append the username as a suffix to the hardware ID:

```cpp
config->setHardwareID(getHardwareId() + "_" + username);
```

### Example Scenario

We enforce a rule where **each license user is allowed only one activation**, but **a single device can host multiple license users simultaneously**.For example, user t\@t.com activates their license on a local machine. This should:

- Increment the license’s total activation count by **1**.
- Increment **that license user’s** total activation count by **1**.
- Assign the computed hardware ID as:
- local\_machine\_hwid\_t\@t.com.

Now, consider two users t\@t1.com and t\@t2.com who both use the same **station machine** under the same license. For each of them, a unique hardware ID will be generated:

- station\_machine\_hwid\_t\@t1.com
- station\_machine\_hwid\_t\@t2.com

This approach ensures that each **license user has a unique hardware ID**, even if they share the same physical device. As a result, **license user-based activation tracking remains unambiguous**, avoiding any inflated or deflated total\_activation counts.

![](https://t4573966.p.clickup-attachments.com/t4573966/04b916d8-10a9-49db-9a07-41e987651247/image.png)

### Switching Machines

If user t\@t1.com wishes to move from the **station machine** to the **local machine**, they must:

1. **Deactivate** the license on the station machine.
2. **Activate** it on the local machine.

![](https://t4573966.p.clickup-attachments.com/t4573966/c0b2f224-3779-4245-bb68-dfe6fc26d248/image.png)

The same rule applies when switching in the opposite direction.

[title] Stripe Integration
[path] Integrations/Stripe/

## Implementation Steps

Follow these steps to configure licensing for products that you sell using Stripe

1. Create product in LicenseSpring platform
2. Create product in Stripe dashboard
3. Add custom attributes to the product price metadata
4. Add webhook endpoint
5. Add restricted api key from Stripe to LicenseSpring platform account
6. Creating payment
7. Generate License Keys

## 1. Create Product in LicenseSpring Platform

1. Log in to `https://saas.licensespring.com/login`
2. Go to **Configure Products → Add new Product** and create a new product

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/wOdApkWWJHMZzDeH6T-He_image.png)



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/HkY6vzMSubZjO2ElFXke1_image.png)



## 2. Create Product in Stripe Dashboard

1. Log in to your Stripe dashboard and go to **Products → Add product**
2. As a part of a product creation process in Stripe, you need to create a **price** for this product. If you select **Recurring** billing type, LicenseSpring integration will create **subscription** license type and use **billing period** from price settings as a **valid duration** in LicenseSpring. If you select **One time** billing type, LicenseSpring will use products default license type value or custom price attribute to set license type in LicenseSpring.
3. Click on **Save product** button in the top right corner of the screen to finish creating a product in Stripe.



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/OrEbUV6z5MXsOH70Rlt_F_image.png)



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/XOsGmDDePmllWIJQyrhQ5_image.png)



## 3. Add Custom Attributes to the Product PRICE Metadata

To properly create licenses LicenseSpring will use product **price** metadata custom attributes. To add attributes to the **price** metadata, go to *Product* page and select the price which you want to customize.



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/M2kf0-71akWsqXHWDkllm_image.png "Select product price")



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/rdY_ZzFPg96mYlprSz0IA_image.png "Edit price metadata")

### 3.1. License Policy

For every product in the LicenseSpring platform you can define one or many license policies which act as a template when creating licenses. License policy can be added to the Stripe products as a price metadata key license\_policy with value of some license policy code. When order is being created via Stripe, our integration will take all the fields, product features and custom fields from included license policy and create the license based on those.

If `license_policy` attribute is not included Stripe integration will use default license policy for the product to create a license.

In case of subscription `license_type` will be always set as `subscription` and `valid_duration` period will use billing period from product price settings.



### 3.2. Custom Attributes

Custom attributes are used to overwrite fields from license policy and to handle some specific use cases which license policies don't cover. Note that `short_code` attribute is always required.

- `short_code` - **required**. Add the product short code you configured LicenseSpring product with.
- `max_activations` - optional, INT. If this field is not included, the default from the product configuration in LicenseSpring will be used.
- `floating_cloud` - optional, INT. If this value is set licenses from this product will be created as floating cloud. This value also sets the total number of machines / users that can concurrently use a floating cloud license ( Max simultaneous license users value in LicenseSpring configuration ). Needs to be less than or equal to max activations attribute value.
- `license_type` - optional, STRING. If this field is not included, the default license type from the product configuration in LicenseSpring is used ( perpetual, time-limited, subscription, consumption ). For recurring product prices, license type can be either **subscription** or **consumption**. In the case of consumption licenses, the total consumptions are **reset** at the start of each billing interval.
- `valid_duration` - optional, STRING. If this field is not included, the default valid\_duration from the product configuration in LicenseSpring is used. The format for this is `N[d/w/m/y]` where N is number and option between d,w,m,y is possible (day, week, month, year - ex. "1y"). **Not applicable for subscription licenses.** - subscription licenses will use billing period from product price settings.
- `enable_maintenance_duration` - optional, BOOL. turns on maintenance capability. If not defined, default from LicenseSpring is used.
- `maintenance_duration` - optional, STRING behaves same as the `valid_duration` field.
- `max_license_users` - optional, INT, limits the number of users which can be added to the licenses -. example: one license with multiple license users. Can be added only for products with **user authorization method**
- `is_license_manager` - optional, BOOL, sets customer as a license manager. Useful on license-key based products where customer is not set as a license manager per default. If you are creating user based licenses, but do not want the customer to be assigned as a license manager, set this as `false`
- `assign_customer_as_user` - optional, BOOL, customer will be automatically assigned to the license as a license user. Can be added only for products with **user authorization method**
- `unpaid_active_license_period` - optional, STRING, used to define a period during which the licenses **remain active** even if they haven't been paid for yet. The format for this is `N[d/w/m/y]` where `N` is a number and `d`, `w`, `m`, or `y` represents days, weeks, months or years respectively (e.g., "3d" for 3 days)
- `added_days` - optional, INT, specifies the number of days to extend the current subscription interval. Applicable only to **subscription** licenses.



### 3.2.1. Single License

In your store, user can select different quantities for a product. Default behaviour is that multiple quantities will result in multiple licenses (both user and license-key based!). If instead, when user selects >1 quantity you want to make a SINGLE license that can be activated multiple times (for license-key based) or a SINGLE license that supports multiple users (for user-based licenses), you need to add this custom attribute: `is_single_license` - optional, BOOL

![](https://kwiki-user-media.s3.amazonaws.com/staging/content/image_widgets/Price_metadata_LmcK6ww.png "Product price metadata")



### 3.2.2. Max Simultaneous License Users from Quantity on a Single License

In case of single floating-cloud license, quantity can be used to determine max simultaneous license users instead of max\_activations for license-key based or number of users for user based products. To enable this, please use this following combination of custom attributes on the product price:

- `floating_users_from_quantity`: true
- `floating_cloud`: 1
- `max_activations` - optional, INT. If this field is not included, the default from the product configuration in LicenseSpring will be used.



### 3.2.3. Product Bundles

Product bundle is a unique type of product in LicenseSpring that requires specific configuration. This section outlines all the currently available **Product Attributes** for product bundles and instructions on how to use them.

:::hint{type="warning"}
Only **one** product bundle can be processed per order. Multiple quantities of the same product bundle **are supported**; however, including two or more **different** product bundles in the **same order** on Stripe is **not** supported.
:::

**How to set up product bundles in LicenseSpring?**

1. Go to the **Products** section in LicenseSpring platform
2. Click the **Add new bundle** button

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/wTUy6_ZK7-I06p4PDQYRS_image.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/wTUy6_ZK7-I06p4PDQYRS_image.png" size="100" caption isUploading="false" width="2988" height="724" darkWidth="2988" darkHeight="724" indent="2"}

3. Insert the desired **Bundle name&#x20;**&#x61;nd **Bundle code**, choose which **Authorization method to use**, and finally, select all the products that you want inside the bundle

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/XJbs1DPEaNQpUQupP0Bti_image.png" signedSrc size="60" width="898" height="1032" position="center" caption darkWidth="898" darkHeight="1032" indent="2"}

4. After the bundle is created, it should look something like the following picture. Take the **Bundle code** value and use it as the `short_code` in the Stripe configuration. (Look at the list below to see all the available **Product attributes** for **bundle products**)

::Image[]{src="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/H3BatFY8_bd8mVVZk6D49_image.png" signedSrc="https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/H3BatFY8_bd8mVVZk6D49_image.png" size="100" caption isUploading="false" width="2464" height="1050" darkWidth="2464" darkHeight="1050" indent="2"}



:::hint{type="info"}
All other setup steps are the same as they are for basic Products. The only difference is in the supported **Product attributes**.
:::

:::hint{type="info"}
If a product bundle contains, for example, three products, then four licenses will be created in LicenseSpring. One license will be for the bundle itself, which can be used for all products within the bundle. The remaining three licenses will be created for each individual product in the bundle. The value of these individual licenses is determined by the **default license policy of each product**.
:::

:::hint{type="warning"}
Each license will include the features defined in the **default license policy** of the product for which the license was created.
:::



**Product Attributes**

- `is_product_bundle` - **required**, BOOLEAN, has to be set to `true`
- `short_code` - **required**, with the code you configured LicenseSpring Product **Bundle** with
- `max_activations`  - optional, INT. If this field is not included, the value from the default license policy on the product in Licensespring will be used.
- `floating_cloud` - optional, INT. If this value is set licenses from this product bundle will be created as floating cloud. This value also sets the total number of machines / users that can concurrently use a floating cloud license ( Max simultaneous license users value in LicenseSpring configuration ). Needs to be **less than or equal** to max activations attribute value.
- `license_type` - optional, STRING. If this field is not included, the default license type of each product inside the bundle configuration in LicenseSpring is used (`perpetual`, `time-limited`, `subscription`, `consumption`). For subscription products license type is always **subscription**.
- `valid_duration` - optional, STRING. If this field is not included, the default valid\_duration of each product inside the bundle configuration in LicenseSpring is used. The format for this is `N[d/w/m/y]` where N is number and option between d,w,m,y is possible (day, week, month, year). **Applicable** for `time-limited` licenses **only**.
- `maintenance_duration`- optional, STRING behaves same as the `valid_duration` field
- `enable_maintenance_duration`- optional, turns on maintenance capability. If not defined, default from LS is used
- `max_license_users` - optional, INT, limits the number of users which can be added to the licenses -. example: one license with multiple license users. Can be added only for products with **user authorization method**
- `is_license_manager` - optional, sets customer as a license manager. Useful on license-key or user-based products where the customer is not set as a license manager by default.
- `assign_customer_as_user` - optional, BOOL, customer will be automatically assigned to the license as a license user. Can be added only for products with **user authorization method**
- `unpaid_active_license_period` - optional, STRING, used to define a period during which the licenses **remain active** even if they haven't been paid for yet. The format for this is `N[d/w/m/y]` where `N` is a number and `d`, `w`, `m`, or `y` represents days, weeks, months or years respectively (e.g., "3d" for 3 days)
- `added_days` - optional, INT, specifies the number of days to extend the current subscription interval. Applicable only to **subscription** licenses.



## 4. Add Webhook Endpoint

LicenseSpring will listen to some events sent from Stripe to create orders and licenses in the platform. To enable this you need to create a Stripe webhook which will send those events to LicenseSpring server.

To create a webhook go to ***Developers*** **->&#x20;*****Webhooks*** and click on **Add endpoint** button.



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/sQVkgLufQxqTKYclPyY7u_image.png)

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8nfk70YfIavbjR9LIWxrw_image.png)

**Endpoint URL** will be

`https://integrations.licensespring.com/api/stripe?uuid={uuid}`

**Example URL**

`https://integrations.licensespring.com/api/stripe?uuid=12345678-7121-6bcb-a355-bbd6b6df0b84`

To retrieve the uuid (api-key) go to **LicenseSpring → Settings → Keys**

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/72DERElhKHmfuwrai_7MD_screenshot-2023-11-08-at-132209.png)



Select these **Events** to listen to:

- **customer.subscription.created** (order and licenses will be created in LicenseSpring)
- **customer.subscription.deleted** (licenses from the subscription will be deactivated)
- **customer.subscription.updated** (licenses from the subscription will be updated with new values ( quantity, policy and trial changes ))
- **invoice.payment\_succeeded** (on successful payment licenses will be prolonged with new Expiration date written in license `validity_period` field)
- **charge.refunded** (licenses associated with the refunded charge will be disabled)



## 5. Add Restricted API Key from Stripe to LicenseSpring Platform Account

LicenseSpring needs limited access to your Stripe account to update **Subscription metadata** after order is created and to fetch and copy **Customer** from Stripe to LicenseSpring.

To enable this create **restricted API key** in your Stripe dashboard. Go to *Developer* -> *API keys* and click on the **Create restricted key** button.



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/IXa9n6VOdUSYEBMw0SN2q_image.png)

The title of this key can be anything you like, but we recommend something relating to LicenseSpring. Set all **permissions** to *Read* except **Subscriptions**, **Invoices** and **Stripe CLI permissions** which need to be set to *Write*.

Save this key and add it to the LicenseSpring account by going to **Settings -> Integrations**.&#x20;

Press **Activate** for Stripe.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/XVrRNOKQCZ9lXliyQuKmS_screenshot-2023-11-08-at-132621.png)

Copy the key to the **Stripe secret key** text field.

Select the **Management API key** and **License API key** (uuid) that you want to use.

The License API key (uuid) **needs to be the same** as the one you used for the **webhook endpoint**

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Cwn6ffpxrloy3v2GtJjdg_screenshot-2023-11-08-at-132715.png)

## 6. Creating Payment

### a) One-Time Products

**With Invoices:**

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/beOA0z4mlHLBdS4YWqxX6_image.png)

To generate an invoice, first select your customer and item (a one-time product). Then, set the payment collection method to 'Autocharge Customer.' Once you've reviewed everything, you can proceed to charge the customer.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Nx7XYwO4vcZSU0LQ9biNH_image.png)



**With Payment Link:**

In the right upper corner click on the '+' sign and then on **Payment Link**

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Ie4qGwOGK_cd7Qcouz3jQ_screenshot-2024-01-17-at-142701.png)

Once the page for payment link creation opens, firstly select the **one-time** product price for which you want to create the link



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/itb1WgkTz9LW7LGquhifW_screenshot-2024-01-17-at-142749.png)

After you've selected the product click on **After payment!**

Make sure to select the **'Create an invoice PDF'** checkbox.

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/jPe-Hk5mVKOQaWCFHy6id_screenshot-2024-01-17-at-142830.png)

### b) Subscription Licenses

When dealing with subscription products, you should utilize a payment link. To do so, first choose 'Payment Link,' then select the product, and finally create the link.&#x20;

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/MaTTd0I3SZ_8fx0-_k2HZ_image.png)



![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/86obH9xZqYk-DvrOG9dAR_image.png "Acessing link and making payment")

After creating the link, access it to complete the payment process.

## 7. Generate License Keys

There are currently two ways how you can create licenses keys which will be then used for licensing your products.

### a) Attaching to Metadata of the New Subscription (**preferred**)

If Stripe API will be used to create subscriptions, attach the generated license keys to the subscription metadata. LicenseSpring integration will use those keys to create licenses in the LicenseSpring platform. More about Stripe API subscriptions methods [**here**](https://stripe.com/docs/api/subscriptions/create)

To generate licenses please use [**this generate\_licenses endpoint**](https://docs.licensespring.com/docs/generate-license-key) from our Management API

Instead of *\{short\_code\_here}* placeholders add a product short code for which you want to use those license keys.

### b) LicenseSpring Updates Subscription Metadata After Order Creation

If you are creating Stripe subscriptions and invoices ( in case of one time order, ex. perpetual licenses ) manually without the ability to create the subscription or invoice with prefilled metadata then LicenseSpring will detect that metadata doesn't contain keys for the product in question and it will generate them automatically. Upon order create is finished, subscriptions / invoice metadata on Stripe will be updated with those license keys.

To access them you can subscribe your application to Stripe `customer.subscription_updated` event in case of a subscription or `invoice.updated` event in case of a one time order.

Alternatively you can fetch the subscription or invoice afterwards using Stripe API.

License keys will be visible on Stripe dashboard on metadata section of the created subscription / invoice.

![](https://kwiki-user-media.s3.amazonaws.com/staging/content/image_widgets/subscription_metadata_x3cKMfv.png "Subscription metadata")




[title] Changelog
[path] Floating Server/Floating Server V1/

## Release Notes

### v1.6.4 - 06.08.2025

- Resolved Docker-related vulnerabilities
- Fixed parameter handling in Floating Register endpoint
- Prevented license deactivation on server shutdown

### v1.6.3 - 15.05.2025

- Updated dependencies
- Fixed bug in unregister\_all endpoint

### v1.6.2 - 13.02.2025

- Fixed air-gapped license activation issue
- Resolved inconsistency in periodic consumption reset
- Updated floating feature registration output to align with SDKs
- Restricted feature registration to only occur during license registration
- Updated License registration output to include updated consumption and floating user count values
- Updated "floating\_not\_available" error code to align with license API

### v1.6.1 - 24.12.2024

- Restricted offline license request reuse
- Prevented offline license request hardware ID mismatches
- Added an endpoint for license feature checks

### v1.6.0 - 19.11.2024

- Support for unlimited licenses per product
- Additional option to handle invalid Hardware Keys
- Added an endpoint to retrieve all licenses associated with a product

### v1.5.1 - 15.10.2024

- Enhanced handling of hardware key validity after device reattachment or server restarts.
- Only a single admin user can be configured initially during setup.
- In authentication mode, the username is now displayed in the user interface.
- Product names are now visible in the UI.
- API and shared keys are no longer visible in the UI for improved security.

### v1.5.0 - 23.09.2024.

- User authentication and role-based access control
- Support for hardware keys and licenses with hardware key requirements
- Storage optimization of file database
- Helm chart - added `hardwareKeySupport` flag - `false` by default
- Helm chart - dependency (Redis) updated to latest chart version 20.1.4
  Please check bitnami offical chart page for breaking changes and upgrade procedures - [**https://artifacthub.io/packages/helm/bitnami/redis**](https://artifacthub.io/packages/helm/bitnami/redis)

### v1.4.12 - 21.08.2024.

- Verbose Error Logging Introduced.
- Verbose Error Logging Introduced.

### v1.4.11 - 25.06.2024.

- Disk usage optimization of file database
- Support for Floating Features
- CVE fixes
- Docker image security fixes
- Helm chart - dependency (Redis) updated to latest chart version 19.5.5
  Please check bitnami offical chart page for breaking changes and upgrade procedures - [**https://artifacthub.io/packages/helm/bitnami/redis**](https://artifacthub.io/packages/helm/bitnami/redis)

### v1.4.10 - 05.04.2024.

- Usage logs CSV fix
- Database initialization fix

### v1.4.9 - 11.03.2024.

- Support for choice between redis or embedded database

### v1.4.8 - 09.02.2024.

- Support for Reset and Unlimited Usage of License and Feature Consumptions
- Consumption Calculations and Synchronization
- Consumption Amounts shows on UI

### v1.4.7 - 04.12.2023.

- Support for whitelabel and custom API url
- Add path and pathType to Igress - helm chart

### v1.4.6 - 14.6.2023.

- JavaScript libraries bundled with Floating Server

### v1.4.5 - 1.6.2023.

- User-based offline licenses

### v1.4.4 - 23.5.2023.

- Database initialization fix

### v1.4.3 - 6.4.2023.

- OpenAPI spec and UI

### v1.4.2 - 22.3.2023.

- Custom expiration system, due to Redis expiration system limitations
- Basic migration system

### v1.4.1 - 16.3.2023.

- Logging error fix

### v1.4.0. - 3.2.2023.

- Redis optimization

### v1.3.3. - 10.1.2023.

- Airgapped licenses
- Unregister all fix
- API error format fix

### v1.3.2. - 14.12.2022.

- HWID fix for MacOS

### v1.3.1. - 10.10.2022.

- Logging improvements
- Online sync improvements
- General bug fixes

### v1.3.0 - 7.9.2022.

- Unified event system (for reporting and sync events)
- Refactored database layer and dependent code
- Not compatible with Badger (embedded DB), only with Redis
- Not backwards compatible

### v1.2.1 - 3.8.2022.

- Consumption activity synced with LicenseSpring

### v1.2.0 - 8.7.2022.

- Licenses are now configured using product code, instead of product name
- Not backwards compatible

### v1.1.9 - 23.6.2022.

- JSON serialization standardized
- Additional fields for APIs

### v1.1.8 - 2.6.2022.

- Reporting database change

### v1.1.7 - 13.5.2022.

- Implemented feature consumption

### v1.1.6 - 28.4.2022.

- License borrowing feature on floating server

### v1.1.5 - 19.4.2022.

- Unregistration UI buttons can now be disabled ([**https://licensespring.kwiki.io/docs/configuration-file**](https://licensespring.kwiki.io/docs/configuration-file))
- More information is sent to LS during license activation, you can see that information under Devices in License details page
- You are able to send more data on Register request, which you can see under Registrations page on the UI.

### v1.1.4 - 31.3.2022.

- logout button
- whitelabel additions
- csv export fix

### v1.1.3 - 21.3.2022.

- remove "unregister", "unregister all"
- licenses bugged (no license key)
- login with wrong password message
- registration page statistics
- registration log (downloadable)
- favicon fix

### v1.1.2 - 1.2.2022.

- Consumption feature: API, UI
- Backwards compatible

### v1.1.1 - 10.1.2022.

- Whitelabeling
- License details page
- "Unregister all" API endpoint
- Not backwards compatible

### v1.1.0 - 23.12.2021.

- Redis support
- High-availability setup
- Not backwards compatible


[title] Salesforce
[path] Integrations/

Salesforce is a leading customer relationship management (CRM) platform that empowers businesses to streamline and enhance their interactions with customers, prospects, and partners.&#x20;

Renowned for its cloud-based architecture, Salesforce offers a comprehensive suite of tools and features, including sales automation, marketing automation, customer service, analytics, and more.&#x20;

By centralizing crucial customer data and automating various processes, Salesforce enables organizations to improve efficiency, boost productivity, and deliver more personalized and effective customer experiences.&#x20;

With its user-friendly interface and scalability, Salesforce has become a cornerstone for businesses aiming to optimize their operations and cultivate lasting customer relationships.

Leveraging our inherent integration with Salesforce, you can seamlessly synchronize your Salesforce account and LicenseSpring platform, effectively bridging these two systems together.

[title] Product Configuration Glossary
[path] Common Scenarios/Glossary/

## **Product Bundles**

[**Product Bundles**](docId\:AS08t1Z5n78m2tQI31_xl) are a specific product type that combines multiple products together. This enables them to be activated and utilized with a single license, streamlining the licensing process.



![Product Bundle Detail Page](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/sdI_UVL9xcnoHlmPGvREI_image.png "Product Bundle Detail Page")

## **Product Code/Name**

When configuring a new application within LicenseSpring, you will be prompted to enter a "short code" known as the product code. These codes consist of a sequence of characters (minimum 2) and serve as a unique identifier for the product. Product codes are typically used for license checks and activations to identify the specific product associated with the license.

The product name, unlike the product code, does not need to be unique. It serves as a means for tracking and identifying a particular product within the LicenseSpring system. The product name provides a human-readable label or description for the product.

For more information, see [**Product Configuration**](docId\:id-0e3F_VWs2HjtyUP6cu).

## **Product Custom Fields**

[**Product Custom Fields**](docId\:rOHBfI4ZxLpqCjcAUk5r3) are similar to license custom fields, with the distinction that the information is associated with the product itself. By default, all licenses associated with the product will inherit the product custom field values. However, if needed, these values can be overridden or customized at the license level using license custom fields.

## Product Versioning

Creating a new version of a product allows you to manage distinct releases of your product, enabling effective version control and management.

For more information, see our [**Product Versioning**](docId\:sz5ImOvmj5QJaWhELsOXt) documentation.



![Creating a New Product Version](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/JrOMzqT5lY8t-2ehK3ELE_image.png "Creating a New Product Version")

### Version Channel

Application channels act as conduits that enable the efficient and secure transfer of data between applications and the queue manager, allowing for seamless communication and facilitating the retrieval of installation files for software updates.

### Version Release Date

The version release date represents the specific date on which a software version is officially launched or made accessible to users, enabling them to track the progression and evolution of a software product over time.

[title] SDK Glossary
[path] Common Scenarios/Glossary/

## Anti-Clock Tampering

Anti-clock tampering incorporates inherent logic to detect any alterations made to the local machine's time in an attempt to circumvent license policies. This mechanism helps maintain the integrity and enforcement of license terms and conditions.&#x20;

Within LicenseSpring, a timestamp inside the local license file is saved every time a local license is saved. During the local license check the SDK will compare the current system datetime with the timestamp from the local license. If the current datetime is older than last timestamp, the SDK will throw an exception, such as `ClockTamperedException`. This exception can only be thrown only during local license checks, and would not apply to online license checks

## Device Variables

Device Variables are key-value pairs defined by the developer, which can be stored on the local computer and sent to the LicenseSpring platform using the `sendDeviceVariables` function. These variables provide additional information or context about the device and can be used for various purposes within the licensing system.&#x20;



![Device Variables Platform Location](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/U_vSd6-Tye_wl65FrJeDo_image.png "Device Variables Platform Location")

## Floating Client

The [**Floating Client**](docId:85OZDMi_CEEi_i5T6ldh7) module focuses on providing floating license features. It handles the management and usage of licenses that can be shared among multiple users or computers.&#x20;

## License Client

The [**Go License Client**](docId:49m1mYA9TAR5rnZoc5HVf) module implements essential license functions such as online and offline license activation/deactivation, trial licenses, consumption tracking, and variable management.&#x20;

## License Activation

[**Activate License (Online Method)**](docId\:Mt2yGm6CJzh2bumU-Gfww) refers to the process of entering the license key into the application, unlocking the associated entitlements. By activating a license key, users can access the full version of a trial application or enable additional features. Activation starts both the validity period and the maintenance period associated with the license key. Depending on the product's configuration, a license key can be activated on one or multiple computers.

## License Check

[**Check License**](docId\:Zh4KFIh_s59TzIBZKeb9o) refers to the process of refreshing the local license file with the latest entitlements stored on the LicenseSpring servers. In the event of an exception, the license check can provide descriptive information about any problems that occurred. Additionally, it is possible to perform a local check on the device without connecting to the backend. This local check is useful for verifying the validity of a license and detecting any tampering attempts, triggering an exception if any issues are detected.

## License Deactivation:&#x20;

License Deactivation involves unbinding the device from the license and reducing the total activation count. The specific outcome of deactivation depends on the license transfer policy in place. Typically, deactivating a license frees it up to be activated on a different device, allowing for license mobility and enabling the license to be utilized elsewhere.

## License Files

When a license is activated, the SDK generates a license file on the user’s machine. This file contains encrypted license information and is required for validating the license locally. The type and location of the license file depends on the activation method.

### Local License File

After an online activation, the SDK automatically creates an encrypted local license file. This file is managed by the SDK and ensures that license checks can be performed without requiring a constant internet connection. The exact location of the file depends on the operating system. You can find detailed instructions on where to locate the license file in your environment in the [**Local License File**](docId\:FkfZHhA-N838tZNrZu0sZ)

### Offline License File

For environments without internet access, licenses are handled using offline activation files. In this case, the first step is to generate an offline activation request file, sometimes referred to as an offline license file. This request file is then submitted to the LicenseSpring server to obtain a matching activation response file, which completes the offline activation process. Detailed instructions for this workflow are available in the  [**Offline Licensing**](docId\:Dl6ntbcC17ZFT8grgSERW)

### License Policy File

Our software is deployed together with a license policy file, which defines the licensing rules for the product. This file is shipped with the application and serves as the foundation for license activation. Instead of relying on direct HTTP requests or manual file exchanges, activation occurs through a series of code exchanges that bind the license to the license policy file. In practice, the license policy file is always included with the product, and when a license is activated, it simply follows the terms defined within that policy. **This file is used exclusively for&#x20;**[**Air-Gapped Licensing**](docId\:cgPsVOYMM4d4C4iohILhS)**&#x20;scenarios**, where internet connectivity is limited or unavailable.

## LicenseFilePath:&#x20;

`LicenseFilePath` refers to the file path location where the local license is stored on your system.

## License Management:

License Management is a Java [**Management SDK**](docId\:oqeHm3FlI2mJ-0AQ8u724) module that offers APIs for generating license keys and placing orders. It facilitates license key management, including creation, modification, and order processing.

## Floating Cloud License

Floating Cloud License is managed entirely through the LicenseSpring cloud platform. Each client activates against the platform and checks out a license when the application starts. This model requires internet connectivity for license checkout, although licenses can be borrowed for temporary offline use. It supports concurrent usage across multiple users and machines, provides real-time monitoring, centralized management, and detailed reporting. This makes it ideal for distributed teams and organizations that require flexibility and visibility.

## Floating Server License

&#x20;Floating Server License is managed locally through a license server hosted in the customer’s environment. Clients check in and out licenses from the local server without needing constant internet access, making it suitable for offline, restricted, or air-gapped environments. While it offers more control over deployment, reporting is limited to local exports unless synchronized with the cloud, and it does not provide the same level of real-time monitoring as the cloud-based model.

## Hardware ID

Hardware ID is a unique identifier assigned to a device and used to activate a license. It links a license to a specific device, preventing unauthorized transfer or use. The LicenseAPI and LicenseManager use the Hardware ID module to generate a unique fingerprint for each device. The default algorithm collects key device-specific attributes and combines them into a single identifier, ensuring that licenses are securely tied to legitimate devices.The algorithm works across different operating systems, abstracting hardware details into a consistent, unique string per device. This approach balances security and usability, providing reliable license enforcement without requiring manual configuration. Detailed explanation of device ID algorithms and implementation guidance, please refer to the [**Hardware ID generation**](docId\:yFnuCniXYZAno8e-sY5I1).

## Virtual Machine Detection&#x20;

Virtual Machine (VM) Detection is a feature that identifies when an application is running in a virtualized environment. It helps enforce licensing rules by preventing unauthorized duplication or use of software on virtual machines. VM detection is useful for protecting your application but may need to be disabled in certain scenarios, such as testing or development environments, to avoid interfering with legitimate use. As an alternative, Hardware Key Self-Provisioning can be used to bind a license to a unique hardware identifier, providing a reliable way to prevent app duplication even when VM detection is turned off. Detailed guidance on VM detection and hardware key self-provisioning, see the [**Virtual Machine Detection doc.**](https://app.archbee.com/docs/FbT_Z5Cu33D-LVZx1fRkU/VF5S2N5h1Ossj_pqeQFgk)




[title] Initial Release Notes
[path] Floating Server/Floating Server V2/

# What’s New (v2)

- **New UI + backend.** Completely rebuilt UI and back-end.
- **Database options.** Choose **SQLite** (easy local/PoC) or **PostgreSQL** (production).
- **Provisioning choices.** Enroll via **YubiKey** or **direct platform** provisioning.
- **Configuration.** Generate, download, and customize a config file (e.g., sync intervals).
- **Offline and Air-gapped support.** Full **license activation & deactivation** flows.
- **Bundles.** Activation/deactivation of **bundle licenses** fully supported.
- **Manual sync.** Trigger a cloud sync on demand.
- **Platforms.** Windows, Linux, and Docker are supported.

# Breaking Changes

- **No in-place upgrade.** v2 does **not** read v1 data stores.
- **Fresh install required.** v2 starts empty, **re-create users, config, and records**.
- **Surface changes.** API/CLI endpoints and commands have been renamed or removed. See the v2 API/CLI docs for the current surface.

# Feature Set

## Licensing & Activation

- Activate/deactivate licenses from the UI.
- **Offline/Air-gap:** UI generates request files for activation and deactivation; process works without internet access.

## Synchronization

- Cloud sync runs on a **customizable schedule** or **manually**.
- Sync updates local state (e.g., **consumption totals**) and fetches remote changes.

## Floating Users (Offline)

- All licenses on the Floating Server are **offline floating**.
- Machines/users/containers can **register** as floating users; they can **unregister** or **borrow time** (if the license allows borrowing).

## Consumption-Based Licensing

- Users can **consume** usage on consumption licenses.
- New **consumption values** are stored locally and synced to the cloud on schedule or on manual trigger.

## Features

- A license may expose **multiple features**; users can register for them.
- Features can themselves be **consumption-based**.

## Bundle Licenses

- **Complete bundle support**: activation, deactivation, and synchronization. Post-activation, full functionality is available for all licenses contained in the bundle.

## Roles & Access Control

- **RBAC:** Admins vs. Users.
- Admins can add/deactivate licenses, unregister users, and manage admin/user accounts.

## Platforms & Deployment

- **Windows**, **Linux**, and **Docker** supported.
- SQLite for quick starts; PostgreSQL recommended for production.


[title] Changelog
[path] Integrations/

## Stripe

:::Changelog{title="v1.3.33. (20.10.2025.)"}
::ChangelogItem{type="added" description="Added a new custom attribute &#x22;added_days&#x22;, which can be used to extend the duration of a subscription interval"}
:::

:::Changelog{title="v1.3.29. (09.09.2025.)"}
::ChangelogItem{type="improved" description="Added handling for the new Stripe API payload change"}
:::

:::Changelog{title="v1.3.27. (14.08.2025.)"}
::ChangelogItem{type="added" description="Added support for Stripe API version “Basil”"}
:::

:::Changelog{title="v1.3.20. (13.02.2025.)"}
::ChangelogItem{type="improved" description="The 'license_type' attribute for recurring prices can now be set to consumption, whereas previously, it was limited to subscription only"}
:::

:::Changelog{title="v1.3.15. (13.11.2024.)"}
::ChangelogItem{type="fixed" description="Resolved an issue where licenses were not created when increasing the subscription quantity"}
:::

:::Changelog{title="v1.3.14. (24.10.2024.)"}
::ChangelogItem{type="added" description="Support for the 'charge.refunded' Stripe event: If an order in Stripe is refunded, all corresponding licenses are disabled in LicenseSpring"}
:::

:::Changelog{title="v1.3.12. (03.10.2024.)"}
::ChangelogItem{type="added" description="Added Product Bundle support"}

::ChangelogItem{type="fixed" description="Stripe customer data is now being stored correctly"}
:::

:::Changelog{title="v1.3.11. (30.09.2024.)"}
::ChangelogItem{type="added" description="Added new custom attribute &#x22;unpaid_active_license_period&#x22;. Used to define a period during which the licenses remain active even if they haven't been paid for yet"}
:::

:::Changelog{title="v1.3.5. (03.07.2024.)"}
::ChangelogItem{type="improved" description="The Stripe integration can now create up to 1,000 licenses per order, an increase from the previous limit of 99"}

::ChangelogItem{type="added" description="If a Stripe event has already been processed, the integration will return a status code of 200 instead of 400"}
:::

:::Changelog{title="v1.2.6. (29.04.2024.)"}
::ChangelogItem{type="fixed" description="Fixed a bug where licenses would be active in LicenseSpring even though the subscription isn't active in Stripe"}
:::

:::Changelog{title="v1.2.5. (26.03.2024.)"}
::ChangelogItem{type="fixed" description="Fixed a bug where validity_period wasn't updated properly when testing events with Stripe test clocks"}
:::

:::Changelog{title="v1.2.4. (22.03.2024.)"}
::ChangelogItem{type="fixed" description="Fixed a bug where custom_fields added to license policies were not receiving the correct values"}
:::

:::Changelog{title="v1.2.2. (29.02.2024.)"}
::ChangelogItem{type="fixed" description="Fixed a bug where max_activations field wasn't displayed properly after subscription quantity increased in Stripe"}

::ChangelogItem{type="fixed" description="Fixed a bug where licenses would be created even though 3DS payment failed in Stripe"}

::ChangelogItem{type="fixed" description="Fixed a bug where, in some cases, all licenses would be enabled after subscription cycle"}
:::



## FastSpring

:::Changelog{title="v1.3.40. (11.02.2026.)"}
::ChangelogItem{type="fixed" description="Fixed an issue that caused subscription upgrades to fail"}
:::

:::Changelog{title="v1.3.38. (20.01.2026.)"}
::ChangelogItem{type="added" description="Added a new custom attribute prefix (product_in_bundle_) to bypass FastSpring’s minimum three-character key limitation, enabling better support for default license policy overrides in product bundles"}
:::

:::Changelog{title="v1.3.31. (23.09.2025.)"}
::ChangelogItem{type="added" description="Added a new custom attribute dynamic_max_activations, which is used to dynamically set the license’s max activations and max users."}
:::

:::Changelog{title="v1.3.26. (07.08.2025.)"}
::ChangelogItem{type="fixed" description="Fixed an issue that prevented updates to single-license subscriptions from processing correctly."}
:::

:::Changelog{title="v1.3.25. (30.07.2025.)"}
::ChangelogItem{type="added" description="Added support for the alphabet parameter in license creation. This parameter allows you to define the set of characters to be used when generating license keys"}

::ChangelogItem{type="added" description="Products included in a product bundle can now individually specify which license policy to use during license creation."}
:::

:::Changelog{title="v1.3.21. (17.02.2025.)"}
::ChangelogItem{type="fixed" description="Fixed a bug that caused the webhook to fail when some of the items had instructions defined in the fulfillments object"}
:::

:::Changelog{title="v1.3.18. (17.01.2025.)"}
::ChangelogItem{type="fixed" description="Resolved an issue where license custom fields were incorrectly set when using a license policy"}

::ChangelogItem{type="added" description="If a FastSpring order has already been created, the integration will return a status code of 200 instead of 400"}
:::

:::Changelog{title="v1.3.17. (30.12.2024.)"}
::ChangelogItem{type="fixed" description="Fixed a bug that would cause the webhook to fail if some of the items in the payload didn't have custom attributes defined"}
:::

:::Changelog{title="v1.3.16. (23.12.2024.)"}
::ChangelogItem{type="added" description="Added new custom attribute is_trial that can be used to create trial licenses while generating non-subscription licenses"}

::ChangelogItem{type="fixed" description="Fixed a bug that would cause max_activations to be set incorrectly for single floating licenses"}
:::

:::Changelog{title="v1.3.15. (13.11.2024.)"}
::ChangelogItem{type="fixed" description="Resolved an issue where licenses were not created when increasing the subscription quantity"}

::ChangelogItem{type="fixed" description="Fixed a bug that prevented the validity_period from updating on single licenses"}
:::

:::Changelog{title="v1.3.14. (24.10.2024.)"}
::ChangelogItem{type="added" description="Added new custom attribute &#x22;disable_licenses_only_on_full_refund&#x22;. When set to true, only licenses that are fully refunded will be disabled. Licenses will remain enabled in the case of partial refunds."}

::ChangelogItem{type="fixed" description="Fixed a bug with subscription refunds"}
:::

:::Changelog{title="v1.3.13. (17.10.2024.)"}
::ChangelogItem{type="added" description="Added license start date"}
:::

:::Changelog{title="v1.3.9. (30.08.2024.)"}
::ChangelogItem{type="added" description="Added new custom attribute &#x22;ignore_product_in_licensespring&#x22;. When set to true, incoming webhooks for the specified product will be ignored, and a 200 status code will be returned to FastSpring as a response."}

::ChangelogItem{type="added" description="Added Product Bundle support."}

::ChangelogItem{type="improved" description="When &#x22;is_license_manager&#x22; attribute is defined, the customers first and last name are also stored."}
:::

:::Changelog{title="v1.3.8. (07.08.2024.)"}
::ChangelogItem{type="improved" description="The FastSpring integration can now create up to 500 licenses per order, an increase from the previous limit of 99"}
:::

:::Changelog{title="v1.3.7. (15.07.2024.)"}
::ChangelogItem{type="added" description="Support for the 'return.created' FastSpring event: If an order in FastSpring is refunded, all corresponding licenses are disabled in LicenseSpring."}
:::

:::Changelog{title="v1.3.5. (03.07.2024.)"}
::ChangelogItem{type="added" description="Every license generated through the FastSpring integration will include an additional attribute in the metadata field called fastspring_subscription_state. The value of this attribute will correspond to the subscription state from FastSpring"}
:::

:::Changelog{title="v1.3.4. (17.06.2024.)"}
::ChangelogItem{type="fixed" description="Fixed a bug where webhooks would fail if some of the products (not all) were defined incorrectly"}
:::

:::Changelog{title="v1.3.1. (07.06.2024.)"}
::ChangelogItem{type="added" description="Added a new product attribute, &#x22;user_max_activations&#x22;, which can update the &#x22;max_activations&#x22; field for a user assigned to a license as a license user"}
:::

:::Changelog{title="v1.2.6. (29.04.2024.)"}
::ChangelogItem{type="fixed" description="Fixed a bug where max_license_users attribute wasn't set correctly when pulled from license policies in LicenseSpring"}
:::

:::Changelog{title="v1.2.3. (06.03.2024.)"}
::ChangelogItem{type="fixed" description="Fixed a bug where custom fields weren't set properly if the order contained more than one product and at least two products had the same product_short_code"}
:::



## Salesforce

:::Changelog{title="v1.3.32. (14.10.2025.)"}
::ChangelogItem{type="added" description="Added the ability to define a start date when creating a license"}

::ChangelogItem{type="improved" description="The valid duration field now auto-fills based on the selected license policy"}
:::

:::Changelog{title="v1.3.31. (23.09.2025.)"}
::ChangelogItem{type="added" description="Added the ability to select product features when creating a license"}

::ChangelogItem{type="added" description="Added a confirmation modal that appears when attempting to delete a license"}
:::

:::Changelog{title="v1.3.30. (15.09.2025.)"}
::ChangelogItem{type="improved" description="Removed product limit"}
:::

:::Changelog{title="v1.3.28. (29.08.2025.)"}
::ChangelogItem{type="added" description="Added license automations"}

::ChangelogItem{type="added" description="Added a Lead Licenses Preview screen"}

::ChangelogItem{type="added" description="Added the ability to delete licenses"}

::ChangelogItem{type="fixed" description="Fixed a bug with the LS Admin permission set"}
:::

:::Changelog{title="v1.3.27. (14.08.2025.)"}
::ChangelogItem{type="added" description="Added new LicenseSpring settings screen"}

::ChangelogItem{type="improved" description="Improved the Account Licenses and Create Order screens"}
:::

:::Changelog{title="v1.3.25. (30.07.2025.)"}
::ChangelogItem{type="added" description="The is_trial parameter has been added to the Order Creation screen"}
:::

:::Changelog{title="v1.3.23. (17.04.2025.)"}
::ChangelogItem{type="improved" description="Added product features and custom fields columns to the licenses table"}

::ChangelogItem{type="added" description="Added possibility to connect existing LicenseSpring customers and accounts"}

::ChangelogItem{type="added" description="Added max_license_users field in the create order screen for user-based licenses"}
:::

:::Changelog{title="v1.3.22. (11.04.2025.)"}
::ChangelogItem{type="fixed" description="Fixed a bug that was preventing user-based licenses from being created"}
:::

:::Changelog{title="v1.3.16. (23.12.2024.)"}
::ChangelogItem{type="improved" description="License update logic"}

::ChangelogItem{type="added" description="License features support"}

::ChangelogItem{type="added" description="License custom fields support"}
:::

:::Changelog{title="v1.3.15. (13.11.2024.)"}
::ChangelogItem{type="added" description="Salesforce Integration V2"}
:::

:::Changelog{title="v1.3.10. (26.09.2024.)"}
::ChangelogItem{type="improved" description="Added PKCE to the OAuth2.0 flow"}
:::

:::Changelog{title="v1.3.6. (04.07.2024.)"}
::ChangelogItem{type="fixed" description="Fixed a bug with customer migrator"}
:::

:::Changelog{title="v1.3.5. (03.07.2024.)"}
::ChangelogItem{type="fixed" description="The integration has been updated to support Salesforce Sandbox instances"}
:::

:::Changelog{title="v1.3.2. (13.06.2024.)"}
::ChangelogItem{type="added" description="Published Salesforce integration"}
:::



## HubSpot

:::Changelog{title="v1.3.39. (28.01.2026.)"}
::ChangelogItem{type="added" description="Added deals cards for previewing licenses from contacts and companies associated with the deal"}
:::

:::Changelog{title="v1.3.38. (20.01.2026.)"}
::ChangelogItem{type="improved" description="Updated the HubSpot OAuth flow to support marketplace installations"}
:::

:::Changelog{title="v1.3.37. (15.12.2025.)"}
::ChangelogItem{type="added" description="Possibility to connect LicenseSpring customer accounts to HubSpot companies"}
:::

:::Changelog{title="v1.3.36. (24.11.2025.)"}
::ChangelogItem{type="improved" description="Improved the “Create LicenseSpring License” workflow action. The product, license policy, customer and trial flag can now be configured at the action level. This allows each workflow to generate a different type of license."}
:::

:::Changelog{title="v1.3.35. (19.11.2025.)"}
::ChangelogItem{type="added" description="Licenses can now be created automatically by using the &#x22;Create LicenseSpring License&#x22; action within any HubSpot Workflow."}
:::

:::Changelog{title="v1.3.34. (13.11.2025.)"}
::ChangelogItem{type="added" description="License app object"}

::ChangelogItem{type="added" description="License card"}

::ChangelogItem{type="improved" description="HubSpot companies can now create licenses for LicenseSpring customer accounts"}
:::

:::Changelog{title="v1.3.24. (25.04.2025.)"}
::ChangelogItem{type="fixed" description="Resolved an issue where license features were not being created based on the configuration defined in their respective products"}
:::

:::Changelog{title="v1.3.22. (11.04.2025.)"}
::ChangelogItem{type="fixed" description="Fixed a bug that was preventing user-based licenses from being created"}
:::

:::Changelog{title="v1.3.19. (05.02.2025.)"}
::ChangelogItem{type="added" description="Possibility to connect LicenseSpring customer to HubSpot contact"}

::ChangelogItem{type="improved" description="Product features can now be selected in the license creation screen"}

::ChangelogItem{type="added" description="Valid duration is pre populated based on the selected license policy in the license creation screen"}
:::

:::Changelog{title="v1.3.16. (23.12.2024.)"}
::ChangelogItem{type="added" description="Published HubSpot integration"}
:::


[title] General
[path] Common Scenarios/Glossary/

## Reseller and Distributor Portals

The distribution portal refers to a comprehensive set of functionalities that empower vendors to enhance their existing License Managers by incorporating distribution capabilities. This enables vendors to assume the role of distributors themselves. With this feature, vendors gain the ability to create and manage their own orders, as well as add licenses to these orders, without relying on direct involvement from the software vendor.

The reseller portal grants license managers the ability to issue licenses within assigned orders while restricting them from creating new orders.

For more information: visit [**Reseller & Distributor Portals**](docId\:NmIbAPRmvlmqOsPZbnsI0)

## HardwareID

Also known as device ID, instance ID, or device fingerprint, the [**Python Hardware (Device) IDs**](docId\:ORDujMleQE_0SSSxxa3bQ) is a hash generated by our SDKs during license activation. It combines various hardware components of a computer, such as the hard disk drive and CPU. The HardwareID serves as a unique identifier for the computer, allowing it to be tracked against the maximum number of activations. If an end user attempts to activate the license on a new machine, it will consume an additional activation from the license. In some cases, developers can override the computation of the HardwareID if they have their own means of identifying the end user or use a custom device fingerprinting algorithm.&#x20;

## License API

The [**License API**](docId:35HkSz8vrz5Kpu1h8EHqb) is specifically designed to be accessed by clients, allowing them to activate, deactivate, and check the status of licenses for a particular software or service.

## License API Key and Shared Key

The License API Key is your company's unique API key used for integration purposes. You can find this key in the "SDK integration" section of your product.

The shared key is a company-specific encryption key utilized for signing requests. It ensures secure communication between entities. You can find this key in the "SDK integration" section of your product.

More information about locating the License API and Shared Key and connecting to the API can be found on our [**Activate a Key-Based License**](docId\:fF0ezEWc-EOi3l8NypEh6) page.



![License API and Shared Key Locations](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/LxQiWTLdrexy5_dGx3J9w_image.png "License API and Shared Key Locations")

## LicenseSpring Vendor Platform

LicenseSpring's [**Vendor Platform**](docId\:tibzWMjTwV3Ia-LWwpmEK) enables users (your staff members) to securely log in and efficiently manage the organization's licenses.

## Management API

The [**Management API**](docId\:abk8afS7gBMtujL_Rd_4p) is intended for organizations to manage and modify existing license entitlements and orders. These APIs possess powerful capabilities and should not be exposed directly to clients or included in client applications.

## User Portal

The [**End-User Portal**](docId\:BOD5TlwkFFKiKasV1ZsrY) allows users to access license information, perform self-service actions, and manage their licenses efficiently.

![End-User Portal](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/Br-CqMy4s1mb53Hu9wdIT_image.png "End-User Portal")


[title] Frequently Asked Questions
[path] /

## Will My Account Be Blocked if I Go Over My API Usage?

You may have noticed that API usage appears on the dashboard of the Vendor platform:

![API Usage Page](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/-I4cpt7SCj_LlO0nqeKMW_image.png "API Usage Page")

If the API usage goes over 100%, the progress bar will become red (and look really scary!). However, nothing bad will happen to your account. License checks still occur, nothing is throttled. However, you may want to proactively contact us to discuss upgrading your account.

## Where Do I Find My Multiple Accounts?

Platform users who have access to multiple accounts will have a drop down in the top left corner.

## Do All Licenses Need to Be a Part of an Order?

Yes, all licenses need to be part of an order. However, you do not need to specify an order ID to issue a license. If you do not specify an orderID when issuing a new license, then LicenseSpring will randomly generate a new orderID.

Trial licenses typically have an orderID generated by Licensespring.

## How Do I Download All of the Licenses Created in LicenseSpring?

Navigate to the license summary page, and click on the "export" button in the right corner:

![Downloading License](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8PZERlyF52DLn0pNswt3s_image.png "Downloading License")

Select the Date Range for which you would like to export to process and click confirm:

![Exporting License](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/xe1SdGxxd28bGIcVYZV1I_image.png "Exporting License")

a CSV file will automatically start downloading.

## What Time Does LicenseSpring Use?

The Licensespring servers are in UTC

## What Constitutes a Device Transfer?

A License will increment the transfer count when it is deactivated from a device and then activated on another device.&#x20;

:::hint{type="info"}
Even known devices will increment the transfer count. For example. Consider 2 devices, A and B. The following sequence will increment the transfer count twice:

- License is activated on A.&#x20;
- License is deactivated on A
- License is activated on B
- License is deactivated on B
- License is activated on A
:::

## What Are the LicenseSpring Public Facing Endpoints?

:::hint{type="warning"}
LicenseSpring public facing endpoints are subject to change. Please check regularly for any updates.

For any additional questions contact support.

As of February 20th users.licensespring.com doesn't have a static IP
:::

IPs:

- 34.250.134.210 (as of June 19th, 2023 09:00 GMT)
- 34.251.49.36 (as of June 19th, 2023 09:00 GMT)
- 52.18.228.254
- 54.78.102.217

| IP                        | License API | Mgmt API & Platform | User portal | Integrations API | Webhooks API |
| ------------------------- | ----------- | ------------------- | ----------- | ---------------- | ------------ |
| 34.250.134.210            | *           | -                   | *           | -                | *            |
| 34.251.49.36              | -           | *                   | -           | *                | -            |
| 52.18.228.254             | *           | -                   | *           | -                | *            |
| 54.78.102.217             | -           | *                   | -           | *                | -            |
| 2a05\:d018:1735\:a703::10 | *           | -                   | *           | -                | *            |
| 2a05\:d018:1735\:a702::10 | -           | *                   | -           | *                | -            |



## Can LicenseSpring be integrated inside Apple Store  ?

**E.g.** if you want to use free app inside AppleStore and you want to implement licensing inside app. Integration LicenseSpring is against the policy of the app store unfortunately. They tend to wall off 3rd party licensing tools ([**https://developer.apple.com/app-store/review/guidelines/#business**](https://developer.apple.com/app-store/review/guidelines/#business))



## When the defined subscription interval has expired, the license stayed in status “Active” although the expiration date is in the past. Why is that? Shouldn't the status switch to “Expired”?

When a **license expires** it will still stay active. If you try to activate that license on a new device you will get error `license_expired`. When you perform `license_check` we there is a field `is_expired` which will be **True** if license expired, otherwise **False**.

## Can we implement a geographical location device tracking?

We recommend using a [**custom field**](https://docs.licensespring.com/license-entitlements/custom-fields), such as `regionsAllowed`, to define entitlements. These restrictions can then be enforced locally within your own codebase or devices. Every device location can be set using [**device variables**](https://docs.licensespring.com/license-api/device-variables)

While implementing georestrictions within the License API and providing a dedicated module in the SDK is on our roadmap, we do not have a clear ETA for this feature at the moment.

## When is Anti-Clock tampering triggered ? Does it stay triggered even when the customer sets their clock back to the correct time?

### SDK

Within the SDK, any attempt to move the system clock to a past date will raise an exception. The SDK keeps track of the last time the license was used online, and if the local clock is earlier than that timestamp, the local check will fail.

### License API

On the server side, the License API rejects requests with signatures older than 15 minutes, further preventing tampering.&#x20;

## How exactly does cacheHardwareID work?

SDKs cache the hardware ID internally, but each time the local license check is used, the SDK recalculates the hardware ID and verifies it against the one embedded in the license file. This ensures that users cannot simply copy the license file to another machine.

## &#x20;How does grace period work ?

Grace period allows users to continue using the license offline for a predefined duration, providing resilience in case of temporary connectivity issues.&#x20;

[**SDK grace period**](https://docs.licensespring.com/sdks/tutorials/best-practices/license-checks#P0sD4)

[**Subscription licenses grace period**](https://docs.licensespring.com/license-entitlements/license-types/time-limited-vs-subscription-licenses#28m_t)

## What is a required password policy for new license users and managers?

Password policy as implemented in LicenseSpring is:

- Minimum 12 characters
- 1 lowercase
- 1 uppercase
- 1 digit
- 1 special character
- it cannot be email or a  recently used password in case of password reset

## What is your brute force login protection policy?

To protect against unauthorized access, the system implements a login attempt limit:

- Users are allowed **up to 10 consecutive incorrect password attempts**.
- After 10 failed attempts, the user is **temporarily blocked**.
- A user can be temporarily blocked **up to three times**, with each block increasing in duration:
  - **1st block**: 15 minutes
  - **2nd block**: 30 minutes
  - **3rd block**: 45 minutes

This policy helps prevent brute-force attacks while still giving users a chance to recover from occasional login mistakes.

[title] Add feature consumption
[path] Floating Server/Floating Server V1/API Reference/consumption/

{
  "id": "0PruA_X2BuDQ6uJmfvcBT",
  "data": {
    "url": "http://localhost:8080/api/v4/add_feature_consumption",
    "name": "Add feature consumption",
    "method": "POST",
    "request": {
      "pathParameters": [],
      "queryParameters": [],
      "headerParameters": [],
      "bodyDataParameters": [
        {
          "kind": "optional",
          "name": "body",
          "type": "object",
          "schema": [
            {
              "kind": "optional",
              "name": "product",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "feature",
              "type": "string",
              "example": ""
            },
            {
              "kind": "optional",
              "name": "consumptions",
              "type": "string",
              "example": ""
            }
          ],
          "isExpanded": true
        }
      ],
      "formDataParameters": []
    },
    "responses": [
      {
        "statusCode": "200",
        "description": "",
        "jsonExample": ""
      }
    ],
    "contentType": "application/json"
  },
  "type": "api-oas-v2",
  "children": [
    {
      "text": ""
    }
  ]
}
[title] Shopify
[path] Integrations/

:::hint{type="info"}
The LicenseSpring Fulfillment app has been developed and maintained by a 3rd party provider.
:::

Software developers can sell their applications on Shopify and issue licenses through LicenseSpring Software, by using the LicenseSpring Fulfillment app for Shopify.

## Resources

[**Full Description on Fulfilment Through Shopify**](https://apps.shopify.com/licensespring-fulfillment)&#x20;

[**Walkthrough Video on Using the Shopify App**](https://www.youtube.com/watch?v=D9keTGudV7U)&#x20;


[title] Glossary
[path] Common Scenarios/

Welcome to the Glossary!&#x20;

This comprehensive collection of terms provides clear definitions and explanations for various concepts related to licensing and software usage.&#x20;

Whether you're a software developer, licensing professional, or simply curious about the different license models and related terms, this glossary will serve as a handy reference guide.&#x20;

From perpetual licenses to subscription models, from node-locking to floating licenses, explore the diverse terminology and gain a deeper understanding of LicenseSpring's lingo!&#x20;











******


[title] HubSpot Integration Installation Guide
[path] Integrations/HubSpot/

## Introduction and Prerequisites

This article is a tutorial on the necessary steps that you need to take to install our LicenseSpring HubSpot integration on your HubSpot instance.

We are assuming that you have a **HubSpot&#x20;**&#x61;nd &#x61;**&#x20;LicenseSpring instance** setup beforehand and that you have the required HubSpot **admin permissions&#x20;**&#x6E;eeded to install applications on it and edit **page views.**

## App Installation

The integration is &#x61;**&#x20;HubSpot app** that can be installed by going to your **settings** view in your **LicenseSpring platform,&#x20;**&#x61;nd clicking on the **Integration&#x20;**&#x74;ab.

![Integrations Tab in LicenseSpring Settings.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/ZJYiL-xxXCl8vj1_MSmTg_screenshot-2024-12-09-at-144928.png "Integrations Tab in LicenseSpring Settings.")

In the integration tab if you scroll down, you will be able to see the HubSpot integration section.

:::hint{type="warning"}
If you do not see the HubSpot integration section, [**contact our sales or support**](https://licensespring.zendesk.com/hc/en-us/requests/new) and they will enable the integration for you.&#x20;
:::

![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/vq_oFY7RrAX0vIzbcX-Fs_image.png)

Choose th&#x65;**&#x20;Management API key** that you want the integration to use in the dropdown component, **HubSpot Account ID&#x20;**&#x61;nd click **Confirm**. This will redirect you to **HubSpot.**


![](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/9RGGXpfw_vpZdYGzcOo12_image.png)

Once redirected you will need to select th&#x65;**&#x20;HubSpot account** on which you want the integration app to be installed on.

![Choose an account for LicenseSpring Integration.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/DrlSqgLpOq29TIPGg1Xoo_screenshot-2024-12-06-at-161623.png "Choose an account for LicenseSpring Integration.")

After clicking **Choose Account** you will be shown all the permissions that the integration needs to function correctly.

![Connecting LicenseSpring App to HubSpot instance.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/tx56LsEI_JGxjrh_fPGFY_screenshot-2024-12-06-at-162207.png "Connecting LicenseSpring App to HubSpot instance.")

After accepting the permissions the app will be installed on your HubSpot instance.

## APP UI / CRM Pages Setup

Once the app is installed, you will need to add the applications UI to the **Contacts** and **Companies CRM pages**.

To do this you will need to go to the HubSpo&#x74;**&#x20;settings page&#x20;**&#x69;n the upper right corner, once in the Settings, you will need to find the **Integrations** section and under integrations there's the **Connected Apps** section.

![Viewing the Connected LicenseSpring Application.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/bk3vk00K8Cn-T1BRnoKMO_screenshot-2024-12-06-at-163141.png "Viewing the Connected LicenseSpring Application.")

This page shows you all your third party apps that you have installed on your instance. Find the **LicenseSpring Integrations** app and click on its blue name.

This will take you to the apps UI setup.

![Apps UI Setup Page.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/PbMXKeK3tVmdniu5hIuRM_screenshot-2024-12-06-at-163928.png "Apps UI Setup Page.")

But before that you will need to click on either the **Company Licenses** or the **Contact Licenses**. In the following example we clicked on the Contact Licenses and this took us to the **View** page for the Contacts Views/Pages where we can see all our views that we have for the Contacts in our HubSpot CRM.&#x20;

In the example we only have the **Default View**, but you might have more then just the Default View, so pick the View that you are currently using or are planning for the integrations UI to live in.

![View Selection Screen.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/PlYmA2EQ7AeoI7Mhn2TK9_screenshot-2024-12-06-at-164112.png "View Selection Screen.")

After Clicking on the View, the **View Editor** will open up for the specific View you have chosen. In the editor you will need to add the Applications UI or as HubSpot calls it a **Card**.

The adding of the **card** depends on your preference but we reccomend that you add the integrations to a **new tab** called **LicenseSpring** on the midddle section on the screen/view. (or on an already existing tabs middle section).&#x20;

In the example below we are going to click on the **Add Cards** and add our already existing card on the **Overview** tab in the middle section of the **View**.

![Add Cards Button.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/z9A92f9duX8BoJLstJrfQ_screenshot-2024-12-06-at-164309.png "Add Cards Button.")

After clicking on the **Add Cards** button, you'll need to search for **Contact License** card under the **Apps** section, and checking the check box next to the **Contact License**.

![Choosing Card Type and Application in Pop-Up.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/21lcKKipeC-wpQ2Zv_JSU_screenshot-2024-12-09-at-144850.png "Choosing Card Type and Application in Pop-Up.")

This will add the card at the bottom of the tab. You can then drag and drop the card wherever you prefer in the tab.

![Moving the card to preferred location.](https://archbee-image-uploads.s3.amazonaws.com/IJdHyjBlO9LOXOrDnWJTx/8iP-vpbvzE0ODTFdP3hcp_screenshot-2024-12-06-at-170012.png "Moving the card to preferred location.")

If you followed all the steps, you are done with the **Contact&#x20;**&#x73;etup and you can click on the **Save and Exit** button on the top right of the screen.

Now you will need to setup the **Company view** also. To do this you will need to repeat the similar steps but for the **Company view**:

1. Go to **Settings** -> **Integrations** -> **Connected Apps** -> **LicenseSpring Integrations**
2. Click on the **Company License** Card.
3. Click on the **Default view**.
4. Add our existing **Card** to the middle of the tab by clicking on the **Add Cards** button and searching for the **Company** **License** and checking the check box.
5. Click on the **Save and Exit** in the upper right corner of the screen.

## Contact Support

If you still have issues with the setup, need answers to certain questions or need additional functionalities added to the integration, please [**contact our LicenseSpring support team**](https://licensespring.zendesk.com/hc/en-us/requests/new).

[title] HubSpot
[path] Integrations/


[title] Single Sign On (SSO)
[path] Common Scenarios/

## Overview

**Single Sign-On (SSO)** is an authentication method that allows users to log in once and gain access to multiple systems without re-entering credentials. By leveraging SSO, organizations can centralize user management, enhance security, and streamline the login experience.

LicenseSpring supports SSO integration to help vendors and end users access our platforms using their existing identity provider (IdP). This is especially useful for teams managing access at scale and seeking to enforce consistent security policies across applications.

LicenseSpring currently supports SSO for two interfaces:

### 1. Vendor Platform SSO

The **Vendor Platform SSO** allows administrators and team members of software vendors to log into the LicenseSpring management dashboard using their organization’s identity provider. This integration supports SAML 2.0 and OIDC protocols, enabling seamless authentication via widely used IdPs such as Okta, Azure AD, Google Workspace, and others.

Vendor platform SSO provides centralized access control and is ideal for managing internal access to license data, product configurations, and customer records. Once configured, organization members can use their corporate credentials to sign in without needing a separate LicenseSpring account.

### 2. User Portal SSO

The **User Portal SSO** enables LicenseSpring customers (software vendors) to offer a unified login experience for their end users and license managers via the hosted **User Portal**. This allows end users and license managers to access license details, activations, and self-service options using credentials from an external identity system.&#x20;

User Portal SSO is commonly used when vendors have an existing user database or authentication flow and wish to avoid requiring separate login credentials for LicenseSpring-hosted services. The User Portal can be configured to accept authentication via the vendor’s IdP, using supported protocols such as SAML or OIDC. This functionality allows vendors to integrate their existing identity infrastructure—such as Google, Azure AD, Okta, Auth0, or any SAML/OIDC-compliant provider—into the user-facing authentication process.

This is particularly beneficial for:

- **Enterprise software** vendors distributing licensed applications across teams or departments
- **B2B SaaS platforms** requiring customer-level user management
- **ISVs** managing a customer base with centralized identity systems

### Next Steps

- To set up SSO for either platform, refer to the respective integration guides:
  - [**Vendor Platform SSO Integration Guide**](https://docs.licensespring.com/common-scenarios/single-sign-on/implementation)
  - [**User Portal SSO Configuration Guide**](https://docs.licensespring.com/common-scenarios/single-sign-on/license-users)

:::hint{type="info"}
LicenseSpring now supports a **new IdP system**, migrating all existing SSO setups and appending the `"legacy-"` prefix.

If you are modifying an existing integration, it is **recommended to delete the old setup and configure a new one** following the updated documentation.

**Key Differences in SSO URLs:**

- User portal SSO (for licensing and user portals) uses **different URL values** from the vendor platform SSO.
- The `/api/v4/sso_url` endpoint should be used to generate login links dynamically.
:::

If you require assistance or have custom SSO requirements, please contact [**LicenseSpring Support**](https://licensespring.zendesk.com/agent/).

