# KEYZY — Full Documentation > KEYZY is a software licensing platform for desktop and plugin developers > (C++, JUCE/audio plugins, C#). It handles license generation, activation, > validation, trials, upgrades and offline licensing via a C++ static library > and a REST API. Credentials compile into the binary; the static library > resists API-hooking, unlike DLL-based licensing schemes. ## Quick Start — C++ Client Library Source: https://www.keyzy.io/docs/developers/tutorials/cpp-quick-start/ ## Prerequisites Before you begin, make sure you have the following ready: - A **KEYZY account** — [create one for free](https://app.keyzy.io/auth/signup) if you haven't already - A **product** and at least one **SKU** created — see [Setting Up Your Product](https://www.keyzy.io/docs/getting-started/setting-up-your-product/) - Your **App ID** and **API Key** — see [Setting Up for Sale](https://www.keyzy.io/docs/getting-started/setting-up-for-sale/) (App Keys section) - A **C++ project** using Visual Studio 2019+, Xcode, or CMake ## Download the Library Download the latest version of the [KEYZY C++ Client Library](https://www.keyzy.io/docs/developers/downloads/cpp-static-library/). Extract the zip file — you'll find `Include` and `Lib` folders organized by platform and compiler. For details on the folder structure, see [C++ Static Library Files and Folders](https://www.keyzy.io/docs/developers/code-samples/configuration/). ## Add to Your Project Add the `Include` folder to your compiler's header search path and the appropriate `Lib` folder to your library search path. Then link against `KeyzyClient`. **Visual Studio:** 1. Right-click your project → Properties 2. C/C++ → Additional Include Directories → add the `Include` path 3. Linker → Additional Library Directories → add the `Lib` path for your configuration (e.g. `R64MDx64v143` for Release x64 with MD runtime on VS2022) 4. Linker → Input → Additional Dependencies → add `KeyzyClient.lib` **Xcode:** 1. Build Settings → Header Search Paths → add the `Include` path 2. Build Settings → Library Search Paths → add the `Lib` path (e.g. `XcodeAppleSiliconIntel64`) 3. Build Phases → Link Binary With Libraries → add `libKeyzyClient.a` **CMake:** ```cmake target_include_directories(your_target PRIVATE /path/to/KeyzyClientLibrary/Include) target_link_directories(your_target PRIVATE /path/to/KeyzyClientLibrary/Lib/Ubuntu) target_link_libraries(your_target KeyzyClient) ``` For a JUCE-specific setup, see the [Add KEYZY to a JUCE Project](https://www.keyzy.io/docs/developers/tutorials/juce-project/) tutorial. ## Configure ProductData Every operation in the library starts with a `ProductData` structure that identifies your product to the KEYZY service: ```cpp #include "KeyzyLicenseActivator.h" Keyzy::ProductData productData( "YOUR_APP_ID", // App ID from App Keys page "YOUR_API_KEY", // API Key from App Keys page "YOUR_PRODUCT_CODE", // Product Code from Products page "YOUR_CRYPTION_KEY" // Encryption key for offline license verification ); ``` You can find your App ID and API Key on the [App Keys](https://app.keyzy.io/appkeys) page, and your Product Code on the [Products](https://app.keyzy.io/products) page in the dashboard. > **Note:** These credentials are compiled into your binary. The KEYZY C++ Client Library is a static library specifically designed for this — unlike dynamic libraries, the communication and verification logic cannot be intercepted through API hooking. For additional binary-level protection, see ShieldVault on the [platform page](https://www.keyzy.io/platform/). ## Create the Activator Create the `KeyzyLicenseActivator` dynamically so you can share the validator and other internal objects across your application. The activator owns shared objects — like the license validator — that you'll retrieve and pass to other parts of your code: ```cpp #include "KeyzyLicenseActivator.h" // Create the activator dynamically — it owns shared objects used across your app std::unique_ptr pActivator = std::make_unique(productData); // Get the validator — you can store and use this anywhere in your application std::shared_ptr pValidator = pActivator->getLicenseValidator(); ``` Keep `pActivator` alive for the lifetime of your application. The validator and other shared objects reference internal state owned by the activator. ## Activate a License Semi-online activation is the most popular activation schema. It connects to the KEYZY server once to download an encrypted license file, then all subsequent validations happen locally — no internet required: ```cpp std::string serialNumber = "XXXX-XXXX-XXXX-XXXX"; // entered by the user Keyzy::LicenseStatus status = pActivator->activateSemiOnline(serialNumber); if (status == Keyzy::LicenseStatus::VALID) { // License activated — unlock your application } else { // Activation failed — see C++ License Status Codes reference // for all possible LicenseStatus values } ``` The library stores the serial number and the encrypted license file on the device. On subsequent launches, you don't need to ask the user for the serial again — just validate. > **Offline License Life:** You can set an Offline License Life for your SKU in the KEYZY dashboard (e.g. 30 days). When set, the downloaded license file expires after that period. Each time `activateSemiOnline()` is called and a new license file is downloaded, the timer resets. So if you set it to 30 days, your application should call `activateSemiOnline()` at least once every 30 days to renew the license file. The no-argument overload makes this easy — it re-downloads the license using the stored serial number, without asking the user again: > > ```cpp > // Renew the license file silently — no serial number needed > Keyzy::LicenseStatus status = pActivator->activateSemiOnline(); > ``` ## Validate on Subsequent Launches Once a license has been activated, use the validator to check it on every launch. For semi-online licenses, validation happens entirely offline using the stored license file: ```cpp Keyzy::LicenseStatus status = pValidator->validateOffline(); if (status == Keyzy::LicenseStatus::VALID) { // License is valid — unlock your application } else { // License is not valid — show the activation form // Common reasons: license expired, license file missing, etc. } ``` You can also retrieve license details from the validator after a successful activation or validation: ```cpp std::string licensee = pValidator->getLicenseeName(); std::string sku = pValidator->getSku(); std::string version = pValidator->getVersion(); ``` ## Next Steps This tutorial covered semi-online activation — one of three activation schemas supported by the library. Explore the other schemas and features: - **[Semi-Online Activation](https://www.keyzy.io/docs/developers/tutorials/cpp-semi-online-activation/)** — Full guide with license renewal and offline license life - **[Online Activation](https://www.keyzy.io/docs/developers/tutorials/cpp-online-activation/)** — Server-validated on every launch - **[Offline Activation](https://www.keyzy.io/docs/developers/tutorials/cpp-offline-activation/)** — No internet connection required at any point - **[Trial Licenses](https://www.keyzy.io/docs/developers/tutorials/cpp-trial-licenses/)** — Client-side and server-side trials - **[Upgrade Licenses](https://www.keyzy.io/docs/developers/tutorials/cpp-upgrade-licenses/)** — Transition users between product versions - **[C++ License Status Codes](https://www.keyzy.io/docs/developers/reference/cpp-license-status-codes/)** — Complete list of all LicenseStatus values - **[C++ Static Library Files and Folders](https://www.keyzy.io/docs/developers/code-samples/configuration/)** — Folder structure and compiler configurations - **[REST API](https://www.keyzy.io/docs/developers/rest-api/general-requirements/)** — Server-side license management --- ## Add KEYZY to a JUCE Project Source: https://www.keyzy.io/docs/developers/tutorials/juce-project/ ## Create a New JUCE Audio Project - Open Projucer - Click to File -> New Project... - Select Audio under Application - Change Project Name - Click to "Create Project..." ![JUCE - Create Audio Project](https://www.keyzy.io/docs/juce-create-audio-project.png) ## Add KEYZY C++ Static Library to The Project - Download [KEYZY C++ Static Library](https://www.keyzy.io/docs/developers/downloads/cpp-static-library/) - Unzip it (for example your Downloads folder) and see KeyzyClientLibraryx.x.x folder - Create "ExternalStaticLibs" folder under your main project folder - Copy KeyzyClientLibraryx.x.x folder to "ExternalStaticLibs" folder - Get back to the Projucer app ### XCode - Select your Xcode exporter - Put "KeyzyClient" text into External Libraries to Link ![JUCE - External Libraries to Link](https://www.keyzy.io/docs/juce-external-libraries-osx.png) - Open Debug configuration under your exporter - Copy this path into Header Search Paths `../../ExternalStaticLibs/KeyzyClientLibraryX.X.X/{{configuration_folder}}/Include` - Copy this path into Extra Library Search Paths `../../ExternalStaticLibs/KeyzyClientLibraryX.X.X/{{configuration_folder}}/Lib` ![JUCE - Header Search Paths - Extra Library Search Paths](https://www.keyzy.io/docs/juce-header-library-paths-osx.png) - Follow the same steps for Release configuration under your exporter ### Windows - Select your Visual Studio exporter - Put "KeyzyClient.lib" text into External Libraries to Link ![External Libraries to Link - Windows](https://www.keyzy.io/docs/juce-external-libraries-win.png) - Open Debug configuration under your exporter - Copy this path into Header Search Paths `$(SolutionDir)..\..\ExternalStaticLibs\KeyzyClientLibraryX.X.X\{{configuration_folder}}\Include\` - Copy this path into Extra Library Search Paths `$(SolutionDir)..\..\ExternalStaticLibs\KeyzyClientLibraryX.X.X\{{configuration_folder}}\Lib\` ![Header and Library Search Paths - Windows](https://www.keyzy.io/docs/juce-header-library-paths-win.png) --- ## C++ License Status Codes Source: https://www.keyzy.io/docs/developers/reference/cpp-license-status-codes/ The `Keyzy::LicenseStatus` enum is returned by activation, validation, deactivation, and deposit methods in the KEYZY C++ Client Library. Use these values to determine the result of any operation and display appropriate messages to your users. ```cpp #include "KeyzyTypes.h" Keyzy::LicenseStatus status = pActivator->activateSemiOnline(serialNumber); ``` ## Success | Status | Description | |--------|-------------| | `VALID` | The operation was successful. The license is valid. | | `ACTIVATION_DELETED` | The license was successfully deactivated on the KEYZY server. | ## License Errors | Status | Description | |--------|-------------| | `INVALID` | The license is invalid. General error for unspecified cases. | | `EXPIRED` | A local (client-only) trial license has expired. Returned by `validateTrialLicense()`. | | `SERIAL_INVALID` | The serial number is invalid or not registered on the KEYZY server. | | `ACTIVATION_DEACTIVATED` | This activation has been deactivated (e.g. by the dashboard or API). | | `REACHED_MAX_NUMBER_OF_HOST` | The serial has reached its maximum number of allowed activations. | ## Subscription and Trial Errors | Status | Description | |--------|-------------| | `SUBSCRIPTION_LICENSE_EXPIRED` | The subscription period has ended. | | `SUBSCRIPTION_LICENSE_NOT_STARTED` | The subscription has a future start date and is not yet active. | | `TRIAL_LICENSE_EXPIRED` | The server-side trial period has ended. | | `TRIAL_LICENSE_NOT_STARTED` | The server-side trial has a future start date and is not yet active. | | `ANOTHER_TRIAL_LICENSE_ALREADY_ACTIVATED` | Another trial license has already been activated on this device. | ## Product and SKU Errors | Status | Description | |--------|-------------| | `PRODUCT_NOT_EXIST` | The product code does not exist on the KEYZY server. | | `PRODUCT_NOT_EXIST_FOR_USER` | The product code does not exist on the KEYZY server. | | `PRODUCT_NOT_ACTIVE` | The product is not active in the dashboard. | | `PRODUCT_NOT_EXIST_FOR_SKU` | The product exists but does not include the SKU connected to the license. | | `SKU_NOT_EXIST` | The SKU does not exist on the KEYZY server. | | `SKU_NOT_ACTIVE` | The SKU is deactivated in the dashboard. | ## Authentication and Connection Errors | Status | Description | |--------|-------------| | `NOT_AUTHORIZED` | The App ID and API Key pair is incorrect. | | `CONNECTION_ERROR` | Network or firewall error. The internet connection is unavailable or blocked. | | `TOO_MANY_REQUESTS` | Too many requests sent in a short time. Wait and retry. | | `NO_ACTIVE_SUBSCRIPTION` | The KEYZY account holder has a subscription issue with the KEYZY service. | ## Network Diagnostic Errors Available in the C++ Client Library **1.9.0 and later**. These are client-detected refinements of `CONNECTION_ERROR`, returned by any method that makes a network request when the call fails at the network layer. They let you show users a more specific, actionable message. If you target an older library version, treat all of these as a generic connection error. | Status | Description | |--------|-------------| | `NETWORK_DNS_FAILED` | DNS resolution failed (both DNS-over-HTTPS and the OS resolver failed). Likely no internet, or DNS is blocked. Ask the user to check their internet connection. | | `NETWORK_REFUSED` | TCP connection refused — typically a firewall blocking outbound HTTPS. Ask the user to check their firewall settings. | | `NETWORK_TIMEOUT` | The connection timed out. Usually a firewall blocking outbound HTTPS or a proxy silently dropping the connection. Ask the user to check firewall/proxy settings. | | `NETWORK_TLS_FAILED` | The TLS handshake failed — corporate SSL inspection, a man-in-the-middle, or a wrong system clock. Ask the user to check the system date/time and any security software. | | `NETWORK_PROXY_REQUIRED` | HTTP 407: the network requires an authenticated proxy. Ask the user to whitelist `api.keyzy.io` with their IT department, or to configure proxy credentials at the OS level. | | `NETWORK_HOSTS_TAMPERED` | The OS resolver returned a private/loopback IP for `api.keyzy.io` — a strong sign of hosts-file or DNS manipulation. Advise the user to check their hosts file. | ## Client-Side Errors | Status | Description | |--------|-------------| | `CANNOT_KEEP_SERIAL` | The library could not store the serial number on the device. | | `CANNOT_KEEP_LICENSE_FILE` | The library could not store the license file on the device. The file path may be incorrect or write permissions may be missing. | | `CLIENT_SERIAL_DOES_NOT_EXIST` | No serial number is stored on the device. The user needs to activate first. | ## Upgrade Errors | Status | Description | |--------|-------------| | `CURRENT_LICENSE_DOES_NOT_EXIST` | The source serial number for the upgrade does not exist on the KEYZY server. | | `UPGRADE_LICENSE_DOES_NOT_EXIST` | The target serial number for the upgrade does not exist on the KEYZY server. | | `UPGRADE_LICENSE_DOES_NOT_MATCH` | The upgrade license does not match the current license for this upgrade path. | ## Deposit and Validation Errors | Status | Description | |--------|-------------| | `SKU_NUMBER_VALIDATION` | The SKU number parameter could not be validated. | | `PRODUCT_CODE_VALIDATION` | The product code parameter could not be validated. | | `NAME_VALIDATION` | The name parameter could not be validated. | | `EMAIL_VALIDATION` | The email parameter could not be validated, or an empty email was supplied to a `register*` call. | | `SERIAL_VALIDATION` | The serial parameter could not be validated (HTTP 422 on register). | | `CODE_VALIDATION` | The code parameter could not be validated (HTTP 422 on register-trial). | | `NO_FREE_LICENSES` | No free licenses are available for this SKU. Generate new licenses in the dashboard. | | `LICENSE_NOT_EXIST_NOT_ASSIGNED_DEALER_ALREADY_DEPOSITED` | The license does not exist, is not assigned to a dealer, or has already been deposited. | | `NAME_OR_EMAIL_VALIDATION` | **Deprecated** since the 2026-04-20 server hardening — never produced by the current server. Kept for binary compatibility; do not rely on it. | --- ## Semi-Online Activation Source: https://www.keyzy.io/docs/developers/tutorials/cpp-semi-online-activation/ Semi-online activation is the most popular activation schema in the KEYZY C++ Client Library. It connects to the KEYZY server once to download an encrypted license file, then all subsequent validations happen locally on the device — no internet required. This makes it ideal for desktop applications, audio plugins, and any software where users expect to work offline after initial activation. ## Prerequisites - The [KEYZY C++ Client Library](https://www.keyzy.io/docs/developers/downloads/cpp-static-library/) integrated into your project — see [Quick Start](https://www.keyzy.io/docs/developers/tutorials/cpp-quick-start/) if you haven't done this yet - A `ProductData` structure configured with your credentials ## Setup Create the activator and obtain the validator. These objects will be used throughout the activation and validation lifecycle: ```cpp #include "KeyzyLicenseActivator.h" Keyzy::ProductData productData( "YOUR_APP_ID", "YOUR_API_KEY", "YOUR_PRODUCT_CODE", "YOUR_CRYPTION_KEY" ); std::unique_ptr pActivator = std::make_unique(productData); std::shared_ptr pValidator = pActivator->getLicenseValidator(); ``` Keep `pActivator` alive for the lifetime of your application. The validator references internal state owned by the activator. ## Activate with a Serial Number When a user enters their serial number for the first time, call `activateSemiOnline()` with the serial. The library connects to the KEYZY server, downloads an encrypted license file, validates it, and stores both the serial and the license file on the device: ```cpp std::string serialNumber = "XXXX-XXXX-XXXX-XXXX"; // entered by the user Keyzy::LicenseStatus status = pActivator->activateSemiOnline(serialNumber); if (status == Keyzy::LicenseStatus::VALID) { // License activated — unlock your application } else { // Activation failed — see Error Handling section below } ``` If activation fails, the library automatically cleans up — no serial or license file remains on the device. ## Validate Offline Once activated, validate the license on every subsequent launch. Semi-online licenses use offline validation — the stored license file is checked locally without contacting the server: ```cpp Keyzy::LicenseStatus status = pValidator->validateOffline(); if (status == Keyzy::LicenseStatus::VALID) { // License is valid — unlock your application } else { // License is not valid — show the activation form } ``` ## Offline License Life and Renewal You can set an **Offline License Life** for your SKU in the [KEYZY dashboard](https://app.keyzy.io). This defines how long the downloaded license file remains valid (e.g. 30 days). After that period, `validateOffline()` will no longer return `VALID`, and the license file needs to be renewed. To renew, call `activateSemiOnline()` without a serial number. The library uses the stored serial to download a fresh license file, resetting the timer: ```cpp // Renew the license file — uses the stored serial, no user input needed Keyzy::LicenseStatus status = pActivator->activateSemiOnline(); ``` Each successful call resets the Offline License Life timer. For example, if you set it to 30 days, your application should call this at least once every 30 days while the user has internet access. > **Tip:** A good pattern is to attempt silent renewal each time your application launches. If the user is online, the license file gets refreshed. If offline, the existing file continues to work until it expires. ## Reading License Details After a successful activation or validation, you can retrieve information about the license from the validator: ```cpp std::string licensee = pValidator->getLicenseeName(); std::string email = pValidator->getLicenseeEmail(); std::string sku = pValidator->getSku(); std::string version = pValidator->getVersion(); std::string type = pValidator->getLicenseType(); std::string info = pValidator->getInfo(); // Dealer-distributed licenses also carry the issuing dealer's name std::string dealerName = pValidator->getDealerName(); // empty string when the license has no dealer ``` `getDealerName()` is available in the C++ Client Library **1.9.0 and later**, and is populated by both the online and offline flows. For a license that was not distributed through a dealer, it returns an empty string. For subscription and trial licenses, you can also read time-related details: ```cpp std::int64_t startTime = pValidator->getStartTime(); std::int64_t endTime = pValidator->getEndTime(); std::uint64_t daysLeft = pValidator->getDaysLeft(); std::uint64_t daysTotal = pValidator->getDaysTotal(); ``` Use these values to display remaining days or expiration warnings to your users. ## Deactivation To deactivate a semi-online license, call `deactivateSemiOnline()`. This contacts the KEYZY server to release the activation slot and deletes the local license file and serial number: ```cpp Keyzy::LicenseStatus status = pActivator->deactivateSemiOnline(); if (status == Keyzy::LicenseStatus::ACTIVATION_DELETED) { // License deactivated — the user can activate on another device } ``` Deactivation requires an internet connection since it needs to notify the KEYZY server. ## Typical Application Flow Here's how a typical application uses semi-online activation: ```cpp // 1. Create the activator and validator (once, at startup) auto pActivator = std::make_unique(productData); auto pValidator = pActivator->getLicenseValidator(); // 2. Try to validate the existing license Keyzy::LicenseStatus status = pValidator->validateOffline(); if (status == Keyzy::LicenseStatus::VALID) { // License is valid — optionally try a silent renewal pActivator->activateSemiOnline(); // refresh if online, ignore if offline } else { // No valid license — show the activation form std::string serial = getSerialFromUser(); // your UI code status = pActivator->activateSemiOnline(serial); if (status != Keyzy::LicenseStatus::VALID) { // Show error to the user } } ``` ## Error Handling All activation and validation methods return a `Keyzy::LicenseStatus` enum. The most common values for semi-online activation are `SERIAL_INVALID`, `REACHED_MAX_NUMBER_OF_HOST`, `CONNECTION_ERROR`, and `SUBSCRIPTION_LICENSE_EXPIRED`. For the complete list of all status codes and their descriptions, see the [C++ License Status Codes](https://www.keyzy.io/docs/developers/reference/cpp-license-status-codes/) reference. ## Next Steps - **[Online Activation](https://www.keyzy.io/docs/developers/tutorials/cpp-online-activation/)** — Server-validated on every launch - **[Offline Activation](https://www.keyzy.io/docs/developers/tutorials/cpp-offline-activation/)** — No internet connection required at any point - **[Trial Licenses](https://www.keyzy.io/docs/developers/tutorials/cpp-trial-licenses/)** — Client-side and server-side trials - **[Upgrade Licenses](https://www.keyzy.io/docs/developers/tutorials/cpp-upgrade-licenses/)** — Transition users between product versions - **[C++ License Status Codes](https://www.keyzy.io/docs/developers/reference/cpp-license-status-codes/)** — Complete list of all LicenseStatus values - **[Quick Start](https://www.keyzy.io/docs/developers/tutorials/cpp-quick-start/)** — Getting started from scratch --- ## Online Activation Source: https://www.keyzy.io/docs/developers/tutorials/cpp-online-activation/ Online activation validates the license with the KEYZY server every time. The serial number is stored on the device, but there is no local license file — each validation requires an internet connection. This is the simplest activation schema and is suitable for applications that always run with internet access. ## Prerequisites - The [KEYZY C++ Client Library](https://www.keyzy.io/docs/developers/downloads/cpp-static-library/) integrated into your project — see [Quick Start](https://www.keyzy.io/docs/developers/tutorials/cpp-quick-start/) if you haven't done this yet - A `ProductData` structure configured with your credentials ## Setup Create the activator and obtain the validator: ```cpp #include "KeyzyLicenseActivator.h" Keyzy::ProductData productData( "YOUR_APP_ID", "YOUR_API_KEY", "YOUR_PRODUCT_CODE", "" // Encryption key is not needed for online activation ); std::unique_ptr pActivator = std::make_unique(productData); std::shared_ptr pValidator = pActivator->getLicenseValidator(); ``` ## Activate with a Serial Number When the user enters their serial number, call `activateOnline()`. The library stores the serial on the device and validates it with the KEYZY server: ```cpp std::string serialNumber = "XXXX-XXXX-XXXX-XXXX"; // entered by the user Keyzy::LicenseStatus status = pActivator->activateOnline(serialNumber); if (status == Keyzy::LicenseStatus::VALID) { // License activated — unlock your application } else { // Activation failed } ``` If activation fails, the library deletes the serial from the device automatically. ## Validate on Every Launch Unlike semi-online activation, online validation contacts the KEYZY server each time. This means your user needs an internet connection on every launch: ```cpp Keyzy::LicenseStatus status = pValidator->validateOnline(); if (status == Keyzy::LicenseStatus::VALID) { // License is valid — unlock your application } else { // License is not valid — show the activation form } ``` After a successful validation, you can retrieve license details: ```cpp std::string licensee = pValidator->getLicenseeName(); std::string email = pValidator->getLicenseeEmail(); std::string sku = pValidator->getSku(); std::string version = pValidator->getVersion(); std::string type = pValidator->getLicenseType(); std::string info = pValidator->getInfo(); // Dealer-distributed licenses also carry the issuing dealer's name std::string dealerName = pValidator->getDealerName(); // empty string when the license has no dealer ``` `getDealerName()` is available in the C++ Client Library **1.9.0 and later**, and is populated by both the online and offline flows. For a license that was not distributed through a dealer, it returns an empty string. For subscription and trial licenses: ```cpp std::int64_t startTime = pValidator->getStartTime(); std::int64_t endTime = pValidator->getEndTime(); std::uint64_t daysLeft = pValidator->getDaysLeft(); std::uint64_t daysTotal = pValidator->getDaysTotal(); ``` ## Deactivation To deactivate an online license, call `deactivateOnline()`. This contacts the KEYZY server to release the activation slot and deletes the serial from the device: ```cpp Keyzy::LicenseStatus status = pActivator->deactivateOnline(); if (status == Keyzy::LicenseStatus::ACTIVATION_DELETED) { // License deactivated — the user can activate on another device } ``` ## Typical Application Flow ```cpp auto pActivator = std::make_unique(productData); auto pValidator = pActivator->getLicenseValidator(); // Try to validate the existing serial with the server Keyzy::LicenseStatus status = pValidator->validateOnline(); if (status == Keyzy::LicenseStatus::VALID) { // License is valid — continue } else if (status == Keyzy::LicenseStatus::CONNECTION_ERROR) { // No internet — decide how to handle this in your application } else { // No valid license — show the activation form std::string serial = getSerialFromUser(); // your UI code status = pActivator->activateOnline(serial); if (status != Keyzy::LicenseStatus::VALID) { // Show error to the user } } ``` > **When to choose online vs semi-online:** Online activation is simpler but requires internet on every launch. If your users may work offline after initial activation, [semi-online activation](https://www.keyzy.io/docs/developers/tutorials/cpp-semi-online-activation/) is the better choice — it downloads an encrypted license file once and validates locally after that. ## Error Handling All activation and validation methods return a `Keyzy::LicenseStatus` enum. The most common values for online activation are `SERIAL_INVALID`, `REACHED_MAX_NUMBER_OF_HOST`, `CONNECTION_ERROR`, and `SUBSCRIPTION_LICENSE_EXPIRED`. For the complete list of all status codes and their descriptions, see the [C++ License Status Codes](https://www.keyzy.io/docs/developers/reference/cpp-license-status-codes/) reference. ## Next Steps - **[Semi-Online Activation](https://www.keyzy.io/docs/developers/tutorials/cpp-semi-online-activation/)** — Activate once online, then validate offline - **[Offline Activation](https://www.keyzy.io/docs/developers/tutorials/cpp-offline-activation/)** — No internet connection required at any point - **[Trial Licenses](https://www.keyzy.io/docs/developers/tutorials/cpp-trial-licenses/)** — Client-side and server-side trials - **[Upgrade Licenses](https://www.keyzy.io/docs/developers/tutorials/cpp-upgrade-licenses/)** — Transition users between product versions - **[C++ License Status Codes](https://www.keyzy.io/docs/developers/reference/cpp-license-status-codes/)** — Complete list of all LicenseStatus values - **[Quick Start](https://www.keyzy.io/docs/developers/tutorials/cpp-quick-start/)** — Getting started from scratch --- ## Offline Activation Source: https://www.keyzy.io/docs/developers/tutorials/cpp-offline-activation/ Offline activation allows your software to validate a license without ever connecting to the internet. The license file is generated externally and delivered to the user, who then loads it into your application. This is ideal for air-gapped environments, studio machines kept offline, or any user who prefers not to require network access at any point. ## Prerequisites - The [KEYZY C++ Client Library](https://www.keyzy.io/docs/developers/downloads/cpp-static-library/) integrated into your project — see [Quick Start](https://www.keyzy.io/docs/developers/tutorials/cpp-quick-start/) if you haven't done this yet - A `ProductData` structure configured with your credentials ## Setup Create the activator and obtain the validator: ```cpp #include "KeyzyLicenseActivator.h" Keyzy::ProductData productData( "YOUR_APP_ID", "YOUR_API_KEY", "YOUR_PRODUCT_CODE", "YOUR_CRYPTION_KEY" // Required for offline activation ); std::unique_ptr pActivator = std::make_unique(productData); std::shared_ptr pValidator = pActivator->getLicenseValidator(); ``` > **Note:** The encryption key (`YOUR_CRYPTION_KEY`) is required for offline activation. You can find it on the [Products](https://app.keyzy.io/products) page in the dashboard. ## Step 1: Get the Host ID Each device has a unique Host ID. Your application needs to retrieve this and display it to the user so they can use it to generate a license file: ```cpp std::string hostId = pValidator->getHostIdHash(); // Display this to the user — e.g. in a dialog, or copy it to the clipboard ``` ## Step 2: Generate the License File The license file is generated externally using the Host ID from Step 1. There are two ways to do this: ### Option A: WooCommerce Plugin If you are using the [KEYZY WooCommerce plugin](https://www.keyzy.io/docs/developers/integrations/woocommerce/install/), your customers can generate the license file directly from your store. The plugin provides a form where the user enters their serial number and Host ID, and downloads the license file. ### Option B: Custom Implementation You can call the [Encrypted File API](https://www.keyzy.io/docs/developers/rest-api/licenses-encrypted-file/) yourself from any language (PHP, C#, Python, JavaScript, etc.). The API returns an encrypted license file. Deliver this file to your user via download, email, or any other method. ## Step 3: Activate with the License File Once the user has the license file on their machine, activate it by passing the file path: ```cpp std::string licenseFilePath = "/path/to/license_file.lic"; // provided by the user Keyzy::LicenseStatus status = pActivator->activateOffline(licenseFilePath); if (status == Keyzy::LicenseStatus::VALID) { // License activated — unlock your application } else { // Activation failed } ``` The library copies and stores the license file on the device. After activation, the original file is no longer needed. ## Validate on Subsequent Launches After activation, validate the license on every launch. Offline validation checks the stored license file locally — no internet required: ```cpp Keyzy::LicenseStatus status = pValidator->validateOffline(); if (status == Keyzy::LicenseStatus::VALID) { // License is valid — unlock your application } else { // License is not valid — show the activation form } ``` After a successful activation or validation, you can retrieve license details: ```cpp std::string licensee = pValidator->getLicenseeName(); std::string email = pValidator->getLicenseeEmail(); std::string sku = pValidator->getSku(); std::string version = pValidator->getVersion(); std::string type = pValidator->getLicenseType(); std::string info = pValidator->getInfo(); // Dealer-distributed licenses also carry the issuing dealer's name std::string dealerName = pValidator->getDealerName(); // empty string when the license has no dealer ``` `getDealerName()` is available in the C++ Client Library **1.9.0 and later**, and is populated by both the online and offline flows. For a license that was not distributed through a dealer, it returns an empty string. For subscription and trial licenses: ```cpp std::int64_t startTime = pValidator->getStartTime(); std::int64_t endTime = pValidator->getEndTime(); std::uint64_t daysLeft = pValidator->getDaysLeft(); std::uint64_t daysTotal = pValidator->getDaysTotal(); ``` ## Offline License Life You can set an **Offline License Life** for your SKU in the [KEYZY dashboard](https://app.keyzy.io). This defines how long the license file remains valid (e.g. 90 days). After that period, `validateOffline()` will no longer return `VALID`. You can show the remaining time to your users so they know when renewal is needed: ```cpp std::int64_t endTime = pValidator->getEndTime(); // endTime is a Unix timestamp — calculate remaining days from current time // e.g. "Your license expires in 12 days" ``` To renew an offline license, the user needs to generate a new license file (repeating Step 2) and activate again. We strongly recommend setting an Offline License Life even for perpetual licenses — it gives you a layer of control over how long a license file stays valid on a device. ## Deactivation Offline deactivation deletes the license file from the device only. It does not contact the KEYZY server — the activation slot on the server is not released: ```cpp bool success = pActivator->deactivateOffline(); ``` > **Note:** Since offline deactivation cannot reach the server, the activation count on the KEYZY server is not decremented. If you need to free up the activation slot, you can do this manually from the [KEYZY dashboard](https://app.keyzy.io) or via the [REST API](https://www.keyzy.io/docs/developers/rest-api/activations-delete/). ## Typical Application Flow ```cpp auto pActivator = std::make_unique(productData); auto pValidator = pActivator->getLicenseValidator(); // Try to validate the existing license file Keyzy::LicenseStatus status = pValidator->validateOffline(); if (status == Keyzy::LicenseStatus::VALID) { // License is valid — continue } else { // No valid license — show the activation form // 1. Display Host ID: pValidator->getHostIdHash() // 2. Let the user browse for the license file std::string filePath = getLicenseFileFromUser(); // your UI code status = pActivator->activateOffline(filePath); if (status != Keyzy::LicenseStatus::VALID) { // Show error to the user } } ``` ## Error Handling All activation and validation methods return a `Keyzy::LicenseStatus` enum. The most common values for offline activation are `INVALID`, `CANNOT_KEEP_LICENSE_FILE`, and `SUBSCRIPTION_LICENSE_EXPIRED`. For the complete list of all status codes and their descriptions, see the [C++ License Status Codes](https://www.keyzy.io/docs/developers/reference/cpp-license-status-codes/) reference. ## Next Steps - **[Semi-Online Activation](https://www.keyzy.io/docs/developers/tutorials/cpp-semi-online-activation/)** — Activate once online, then validate offline - **[Online Activation](https://www.keyzy.io/docs/developers/tutorials/cpp-online-activation/)** — Server-validated on every launch - **[Trial Licenses](https://www.keyzy.io/docs/developers/tutorials/cpp-trial-licenses/)** — Client-side and server-side trials - **[Upgrade Licenses](https://www.keyzy.io/docs/developers/tutorials/cpp-upgrade-licenses/)** — Transition users between product versions - **[C++ License Status Codes](https://www.keyzy.io/docs/developers/reference/cpp-license-status-codes/)** — Complete list of all LicenseStatus values - **[Quick Start](https://www.keyzy.io/docs/developers/tutorials/cpp-quick-start/)** — Getting started from scratch --- ## Trial Licenses Source: https://www.keyzy.io/docs/developers/tutorials/cpp-trial-licenses/ Trial licenses let potential customers try your software for a limited period. KEYZY's server-side trials are fully managed — you can track who is trialing, extend trial periods, and communicate with prospects. Since server-side trials go through the KEYZY service, trial licenses follow the same activation and validation flow as perpetual and subscription licenses. The only difference is how the serial number is obtained: your application can request a trial serial directly from the KEYZY server, or you can distribute trial serials through your website or other channels. This tutorial shows how to request and activate a trial serial using the C++ Client Library. ## Prerequisites - The [KEYZY C++ Client Library](https://www.keyzy.io/docs/developers/downloads/cpp-static-library/) integrated into your project — see [Quick Start](https://www.keyzy.io/docs/developers/tutorials/cpp-quick-start/) if you haven't done this yet - A `ProductData` structure configured with your credentials - A **trial SKU** created in the [KEYZY dashboard](https://app.keyzy.io) with trial licenses generated for it ## Setup Create the activator and obtain the deposit handler and validator: ```cpp #include "KeyzyLicenseActivator.h" Keyzy::ProductData productData( "YOUR_APP_ID", "YOUR_API_KEY", "YOUR_PRODUCT_CODE", "YOUR_CRYPTION_KEY" ); std::unique_ptr pActivator = std::make_unique(productData); std::shared_ptr pDepositHandler = pActivator->getLicenseDepositHandler(); std::shared_ptr pValidator = pActivator->getLicenseValidator(); ``` ## Register a Trial Use `registerTrial()` to request a trial license from the KEYZY server. You need to provide the SKU number for your trial SKU. Optionally, you can pass the user's name and email to track the prospect: ```cpp Keyzy::LicenseInfo licenseInfo; Keyzy::LicenseStatus status = pDepositHandler->registerTrial( licenseInfo, "YOUR_TRIAL_SKU_NUMBER", "Jane Doe", // optional — licensee name "jane@example.com" // optional — licensee email ); if (status == Keyzy::LicenseStatus::VALID) { // Trial registered — licenseInfo now contains the trial details std::string serialNumber = licenseInfo._serialNumber; std::int64_t startTime = licenseInfo._startTime; std::int64_t endTime = licenseInfo._endTime; } else { // Registration failed — see Error Handling section below } ``` If successful, the KEYZY server deposits a trial license and returns the serial number along with start and end times. ## Activate the Trial Once you have the trial serial number, activate it using any of the standard activation methods. Semi-online is the most common choice: ```cpp status = pActivator->activateSemiOnline(licenseInfo._serialNumber); if (status == Keyzy::LicenseStatus::VALID) { // Trial activated — unlock your application } ``` The trial serial behaves exactly like a purchased serial from this point forward. All standard activation schemas work: [semi-online](https://www.keyzy.io/docs/developers/tutorials/cpp-semi-online-activation/), [online](https://www.keyzy.io/docs/developers/tutorials/cpp-online-activation/), and [offline](https://www.keyzy.io/docs/developers/tutorials/cpp-offline-activation/). ## Validate the Trial Validation works the same as any other license. For semi-online activated trials, use offline validation: ```cpp Keyzy::LicenseStatus status = pValidator->validateOffline(); if (status == Keyzy::LicenseStatus::VALID) { // Trial is still active } else if (status == Keyzy::LicenseStatus::TRIAL_LICENSE_EXPIRED) { // Trial period has ended — prompt the user to purchase } ``` ## Show Remaining Time Display the remaining trial period to your users: ```cpp std::uint64_t daysLeft = pValidator->getDaysLeft(); std::uint64_t daysTotal = pValidator->getDaysTotal(); // e.g. "5 days left of your 14-day trial" ``` > **Tip:** Showing the remaining days creates a sense of urgency and helps convert trial users into paying customers. ## Duplicate Trial Prevention KEYZY prevents the same device from activating multiple trial licenses for the same product. If a user tries to register a second trial, `registerTrial()` returns `ANOTHER_TRIAL_LICENSE_ALREADY_ACTIVATED`. ## Typical Application Flow ```cpp auto pActivator = std::make_unique(productData); auto pDepositHandler = pActivator->getLicenseDepositHandler(); auto pValidator = pActivator->getLicenseValidator(); // 1. Check for an existing license (purchased or trial) Keyzy::LicenseStatus status = pValidator->validateOffline(); if (status == Keyzy::LicenseStatus::VALID) { // License is valid — continue } else if (status == Keyzy::LicenseStatus::TRIAL_LICENSE_EXPIRED) { // Trial expired — show purchase prompt } else { // No valid license — offer trial or activation // If user wants to try: Keyzy::LicenseInfo info; status = pDepositHandler->registerTrial(info, "YOUR_TRIAL_SKU_NUMBER"); if (status == Keyzy::LicenseStatus::VALID) { pActivator->activateSemiOnline(info._serialNumber); } else if (status == Keyzy::LicenseStatus::ANOTHER_TRIAL_LICENSE_ALREADY_ACTIVATED) { // Already trialed — show purchase prompt only } // If user has a purchased serial: // pActivator->activateSemiOnline(purchasedSerial); } ``` ## Collecting Contact Information The `name` and `email` parameters in `registerTrial()` are optional but highly recommended. Collecting contact information during trial registration allows you to: - Follow up with trial users before their trial expires - Offer discounts or extensions to engaged prospects - Understand your trial-to-purchase conversion rate You can view all trial registrations and their contact information on the [Licenses](https://app.keyzy.io/licenses) page in the dashboard. ## Error Handling The most common `LicenseStatus` values for trial operations are `ANOTHER_TRIAL_LICENSE_ALREADY_ACTIVATED`, `TRIAL_LICENSE_EXPIRED`, `TRIAL_LICENSE_NOT_STARTED`, `NO_FREE_LICENSES`, and `SKU_NOT_ACTIVE`. For the complete list of all status codes and their descriptions, see the [C++ License Status Codes](https://www.keyzy.io/docs/developers/reference/cpp-license-status-codes/) reference. ## Next Steps - **[Semi-Online Activation](https://www.keyzy.io/docs/developers/tutorials/cpp-semi-online-activation/)** — Most common activation schema for trials - **[Online Activation](https://www.keyzy.io/docs/developers/tutorials/cpp-online-activation/)** — Server-validated on every launch - **[Offline Activation](https://www.keyzy.io/docs/developers/tutorials/cpp-offline-activation/)** — No internet connection required - **[Upgrade Licenses](https://www.keyzy.io/docs/developers/tutorials/cpp-upgrade-licenses/)** — Transition trial users to paid versions - **[C++ License Status Codes](https://www.keyzy.io/docs/developers/reference/cpp-license-status-codes/)** — Complete list of all LicenseStatus values - **[Quick Start](https://www.keyzy.io/docs/developers/tutorials/cpp-quick-start/)** — Getting started from scratch --- ## Upgrade Licenses Source: https://www.keyzy.io/docs/developers/tutorials/cpp-upgrade-licenses/ Upgrade licenses let your existing customers transition from their current version or edition to a newer one. A user with *My Product Standard* can upgrade to *My Product Gold*, or a user on *V1* can upgrade to *V2*. The upgrade process involves two serial numbers: the **source** (current license) and the **target** (upgrade license). The KEYZY server validates the upgrade path, deletes the source license, and makes the target available for activation. ## Prerequisites - The [KEYZY C++ Client Library](https://www.keyzy.io/docs/developers/downloads/cpp-static-library/) integrated into your project — see [Quick Start](https://www.keyzy.io/docs/developers/tutorials/cpp-quick-start/) if you haven't done this yet - A `ProductData` structure configured with your credentials - An **upgrade license** created in the [KEYZY dashboard](https://app.keyzy.io/licenses) — when generating licenses, mark them as upgrade licenses and select which SKU to upgrade from ## Setup Create the activator and obtain the validator: ```cpp #include "KeyzyLicenseActivator.h" Keyzy::ProductData productData( "YOUR_APP_ID", "YOUR_API_KEY", "YOUR_PRODUCT_CODE", "YOUR_CRYPTION_KEY" ); std::unique_ptr pActivator = std::make_unique(productData); std::shared_ptr pValidator = pActivator->getLicenseValidator(); ``` ## Upgrade Using the Stored Serial (Recommended) If the user's current license is already activated on the device, the source serial is stored locally. You only need to provide the target (upgrade) serial: ```cpp std::string targetSerial = "TARG-ETSE-RIAL-XXXX"; // the upgrade serial Keyzy::LicenseStatus status = pActivator->upgradeLicense(targetSerial); if (status == Keyzy::LicenseStatus::VALID) { // Upgrade successful on the server — now activate the target serial status = pActivator->activateSemiOnline(targetSerial); } else { // Upgrade failed } ``` ## Upgrade with Explicit Serials If you need to provide both serials explicitly (e.g. the source serial is not stored on the device), use the two-parameter overload: ```cpp std::string sourceSerial = "SOUR-CESE-RIAL-XXXX"; // current license std::string targetSerial = "TARG-ETSE-RIAL-XXXX"; // upgrade license Keyzy::LicenseStatus status = pActivator->upgradeLicense(sourceSerial, targetSerial); if (status == Keyzy::LicenseStatus::VALID) { // Upgrade successful on the server — now activate the target serial status = pActivator->activateSemiOnline(targetSerial); } else { // Upgrade failed } ``` ## Important: Activate After Upgrade The `upgradeLicense()` method only performs the upgrade on the KEYZY server. It does not activate the new license or store the target serial on the device. After a successful upgrade, you must call one of the activation methods to activate the target serial: ```cpp // Choose the activation schema that matches your setup pActivator->activateSemiOnline(targetSerial); // or pActivator->activateOnline(targetSerial); // or pActivator->activateOffline(licenseFilePath); ``` ## Choosing the Path Up Front Before showing the upgrade form, check whether a license is already active on the device and choose the UI path accordingly. Call `validateOnline()` on the validator — it takes no serial (it uses the serial already stored on the device) and only reads the status; it does not activate anything. ``` Upgrade starts │ validateOnline() │ ┌───────┴───────────────────────┐ VALID not VALID (license on device) (CLIENT_SERIAL_DOES_NOT_EXIST) │ │ 1 field: 2 fields: target serial source + target serial │ │ upgradeLicense(target) upgradeLicense(source, target) └────────────────┬───────────────┘ │ activate (activateOnline / activateSemiOnline) │ unlock new version ``` The example below follows the diagram end to end: ```cpp // Upgrade starts — first check what is already on the device, // without asking the user for anything yet. Keyzy::LicenseStatus status = pValidator->validateOnline(); std::string targetSerial; if (status == Keyzy::LicenseStatus::VALID) { // A license is already active — show a single field for the upgrade (target) serial targetSerial = getTargetSerialFromUser(); status = pActivator->upgradeLicense(targetSerial); } else // CLIENT_SERIAL_DOES_NOT_EXIST — no license on this device { // Show two fields: the current (source) serial and the upgrade (target) serial std::string sourceSerial = getSourceSerialFromUser(); targetSerial = getTargetSerialFromUser(); status = pActivator->upgradeLicense(sourceSerial, targetSerial); } // Both paths converge — activate the target serial after the upgrade if (status == Keyzy::LicenseStatus::VALID) { status = pActivator->activateOnline(targetSerial); // or activateSemiOnline if (status == Keyzy::LicenseStatus::VALID) { // Upgrade complete — unlock the new version/edition } } ``` ## WooCommerce Integration If you are using the [KEYZY WooCommerce plugin](https://www.keyzy.io/docs/developers/integrations/woocommerce/upgrade/), your customers can perform the upgrade directly from your store. The plugin provides an upgrade form where the user enters both serial numbers, and the upgrade is handled automatically on the server side. ## Error Handling The most common `LicenseStatus` values for upgrade operations are `UPGRADE_LICENSE_DOES_NOT_MATCH`, `UPGRADE_LICENSE_DOES_NOT_EXIST`, `CURRENT_LICENSE_DOES_NOT_EXIST`, and `CLIENT_SERIAL_DOES_NOT_EXIST`. For the complete list of all status codes and their descriptions, see the [C++ License Status Codes](https://www.keyzy.io/docs/developers/reference/cpp-license-status-codes/) reference. ## Next Steps - **[Semi-Online Activation](https://www.keyzy.io/docs/developers/tutorials/cpp-semi-online-activation/)** — Most common activation schema after upgrade - **[Online Activation](https://www.keyzy.io/docs/developers/tutorials/cpp-online-activation/)** — Server-validated on every launch - **[Offline Activation](https://www.keyzy.io/docs/developers/tutorials/cpp-offline-activation/)** — No internet connection required - **[Trial Licenses](https://www.keyzy.io/docs/developers/tutorials/cpp-trial-licenses/)** — Let users try before they buy - **[C++ License Status Codes](https://www.keyzy.io/docs/developers/reference/cpp-license-status-codes/)** — Complete list of all LicenseStatus values - **[Quick Start](https://www.keyzy.io/docs/developers/tutorials/cpp-quick-start/)** — Getting started from scratch --- ## C++ Coding Samples Source: https://www.keyzy.io/docs/developers/code-samples/cpp/ Please download our [C++ Static Library](https://www.keyzy.io/docs/developers/downloads/cpp-static-library/) in the Downloads section. It has full samples for online, semi-online and offline activation/validation in its documentation. --- ## C# Coding Samples Source: https://www.keyzy.io/docs/developers/code-samples/csharp/ ## Activate / Validate a License ```csharp // https://restsharp.dev/ using System; using RestSharp; var client = new RestClient("https://api.keyzy.io/v2/licenses/valid"); client.Timeout = -1; var request = new RestRequest(Method.POST); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{\n\t\"app_id\": \"your-app-id\",\n \"api_key\": \"your-api-key\",\n \"host_id\": \"host-id\",\n \"serial\": \"the-serial-number\", \n \"code\": \"product-code\",\n \"version\": \"2.0\",\n \"device_tag\": \"device-tag\"\n}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); Console.WriteLine(response.Content); ``` ## Activations - Get Activation Objects for a License ```csharp // https://restsharp.dev/ using System; using RestSharp; var client = new RestClient("https://api.keyzy.io/v2/activations/LICENSE_SERIAL_NUMBER?app_id=YOUR_APP_ID&api_key=YOUR_API_KEY"); client.Timeout = -1; var request = new RestRequest(Method.GET); IRestResponse response = client.Execute(request); Console.WriteLine(response.Content); ``` ## Activation - Delete an Activation ```csharp using System; using RestSharp; var client = new RestClient("https://api.keyzy.io/v2/activations/ACTIVATION_ID?app_id=YOUR_APP_ID&api_key=YOUR_API_KEY"); client.Timeout = -1; var request = new RestRequest(Method.DELETE); request.AlwaysMultipartFormData = true; IRestResponse response = client.Execute(request); Console.WriteLine(response.Content); ``` ## How To Obtain Host ID in Windows Systems ```csharp using System; using Microsoft.Win32; RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Cryptography"); //if it does exist, retrieve the stored values if (key != null) { Console.WriteLine("Device ID: " + key.GetValue("MachineGuid")); key.Close(); } ``` --- ## C++ Static Library Files and Folders Source: https://www.keyzy.io/docs/developers/code-samples/configuration/ KEYZY C++ Client Library supports Ubuntu, Windows, OSX and iOS. The client library has Include and Lib folders for linking and compiling. ## Windows The client library supports Visual Studio 2019 and Visual Studio 2022 programming tools. Visual Studio named 2019 as v142 and 2022 as v143. The client library has 2 folders for windows. VS2019 and VS2022. Each of them has 8 folders. Folder naming shows some details. - Each folder can start with D or R. D stands for Debug and R stands for Release. - Continues with 64 or 86. The 64 stands for x64 architecture and the 86 stands for x86 architecture. - Continues with MD or MT. This is a special setting for Visual Studio. Basically, if you distribute Visual Studio C DLL files with your installer, you can use MD. If you don't distribute the DLL files, you can use MT then the compiler adds all library objects to your executable. Please find the details with this link. - Continues with x64 or Win32. They express 64 bits or 32 bits. - Lastly, it continues with the visual studio programming tool version, v14x. ## OSX The client library has two folders for the OSX platform. Each library is compiled against Apple's universal library format. - XcodeAppleSiliconIntel64 supports Arm64 and Intel64 architectures as one universal binary file. - XcodeIntel32Intel64 supports Intel32 and Intel64 architectures as one universal binary file. ## iOS The client library has the XcodeiOS folder for the iOS platform. It has two folders: - arm64_armv7: supports arm64 and armv7 universal binary. It can be used for any iOS device. - iPhone11Simulator: supports iPhone11 simulator. ## Ubuntu The client library supports the 22.04 version of 64 bits Ubuntu distribution. --- ## C++ Static Library Source: https://www.keyzy.io/docs/developers/downloads/cpp-static-library/ The KEYZY C++ Client Library is a static library that you link into your application to handle license activation, validation, trials, and upgrades. It supports online, semi-online, and offline activation schemas. ## Latest Version [Download C++ Client Library v1.9.0](https://keyzy-downloads.s3.us-east-1.amazonaws.com/KeyzyClientLibrary1.9.0.zip) — Windows, macOS, Linux ### What's included - Pre-built static libraries for each platform - Header files (`KeyzyLicenseActivator.h`, `KeyzyLicenseValidator.h`, `KeyzyTypes.h`) - Windows: x86 and x64 (MSVC v142, v143) - macOS: Universal binary (Intel x86_64 + Apple Silicon arm64) - Linux: x64 (Ubuntu 22.04) ### What's new in v1.9.0 - `KeyzyLicenseValidator::getDealerName()` — for dealer-distributed licenses, the library now exposes the issuing dealer's name so your application can display it. Non-dealer licenses return an empty string. - Network diagnostic status codes — `CONNECTION_ERROR` is now refined into `NETWORK_DNS_FAILED`, `NETWORK_REFUSED`, `NETWORK_TIMEOUT`, `NETWORK_TLS_FAILED`, `NETWORK_PROXY_REQUIRED` and `NETWORK_HOSTS_TAMPERED`, so you can show users a specific, actionable message instead of a generic connection error. The change is additive: existing `switch (status)` code keeps working unchanged, and the new values are only reached once you add explicit cases for them. See the [C++ License Status Codes](https://www.keyzy.io/docs/developers/reference/cpp-license-status-codes/) reference. ### Upgrading from v1.7.x One behaviour change landed between v1.7.1 and v1.9.0 and applies as soon as you upgrade: - `registerTrial()` and `registerOfflineDistributedLicense()` now require a non-empty email. The server made email mandatory on 2026-04-20, and the library mirrors that: an empty email is rejected immediately with `EMAIL_VALIDATION`, without a network request. If your integration calls either method without an email, supply one before upgrading. - `SERIAL_VALIDATION` and `CODE_VALIDATION` were added for per-field validation failures on those two calls. `NAME_OR_EMAIL_VALIDATION` is deprecated and is no longer produced by the server; it remains in the enum for binary compatibility. See the [folder arrangement and configuration guide](https://www.keyzy.io/docs/developers/code-samples/configuration/) for setup instructions. ## Getting Started After downloading, follow the [C++ Quick Start](https://www.keyzy.io/docs/developers/tutorials/cpp-quick-start/) tutorial to integrate the library into your project and activate your first license. ## Previous Versions **v1.7.1** — Windows, macOS, Linux - Windows: Fixed dynamic runtime (MD) library configuration for all build variants. Static runtime (MT) builds were not affected. **v1.7.0** — Windows, macOS, Linux - Single-parameter `upgradeLicense(targetSerial)` in `KeyzyLicenseActivator` - Improved HTTP networking layer - Multiple security hardening improvements - Linux TLS backend switched from OpenSSL to mbedTLS - Platform TLS backends: Secure Transport (macOS), Schannel (Windows), mbedTLS (Linux) **v1.4.0** — Windows, macOS (OSX), iOS, Linux (Ubuntu 18.04 64-bit) --- ## WooCommerce Plugin Source: https://www.keyzy.io/docs/developers/downloads/woocommerce-plugin/ The KEYZY WooCommerce Plugin (KeyzyWc) connects your WooCommerce store to KEYZY. When a customer completes a purchase, the plugin automatically registers a license and displays the serial number on the order page. ## Latest Version [Download KeyzyWc v1.4.4](https://keyzy-downloads.s3.us-east-1.amazonaws.com/keyzywc1.4.4.zip) ### Features - Automatic license registration on purchase - Serial number display on the order confirmation and My Account pages - Offline activation support — customers can enter their Host ID and download a license file - License upgrade form for existing customers - Batch API requests for faster page load times - Customizable CSS classes for styling the license area ### What's new in v1.4.4 - Fixed a crash on the downloads page when an order contained a product without an SKU (for example, a deleted or misconfigured product) - Fixed an "Array to string conversion" PHP notice when logging API error messages the server returned as an array These are the changes since v1.4.2 (the v1.4.3 fixes); v1.4.4 additionally aligns internal version numbers. ## Installation For setup instructions, see the [WooCommerce Plugin Installation](https://www.keyzy.io/docs/developers/integrations/woocommerce/install/) guide. ## Related Guides - [Register Your Product](https://www.keyzy.io/docs/developers/integrations/woocommerce/register-product/) — connect your WooCommerce product to an SKU - [Subscription Licenses](https://www.keyzy.io/docs/developers/integrations/woocommerce/subscription/) — set up recurring subscriptions - [Upgrade Licenses](https://www.keyzy.io/docs/developers/integrations/woocommerce/upgrade/) — enable license upgrades from your store - [Offline Licensing with WooCommerce](https://www.keyzy.io/docs/getting-started/offline-licensing-woocommerce/) — set up offline activation --- ## General Requirements Source: https://www.keyzy.io/docs/developers/rest-api/general-requirements/ Before you start using the Keyzy API, it's crucial that all your requests comply with the following general requirements. These rules are designed to ensure the security, stability, and fair use of our API. ### Mandatory HTTP Headers | Header Name | Description | Example Value | | --- | --- | --- | | `User-Agent` | A unique string that identifies your client application. **Must not be empty.** | `MyCRM/1.0` or `AcmeApp/2.1.5` | | `Content-Type` | Specifies the format of the data you are sending in `POST`, `PUT`, or `PATCH` requests. **JSON format is strongly recommended.** | `application/json` | #### Why is a `User-Agent` Header Mandatory? Requests with an empty `User-Agent` are typically made by simple scripts, scrapers, or malicious actors. By blocking these requests, we protect our API from abuse and ensure our resources are reserved for legitimate, well-behaved clients. --- ## Errors Source: https://www.keyzy.io/docs/developers/rest-api/errors/ KEYZY uses conventional HTTP response codes to indicate the success or failure of an API request. In general: Codes in the `2xx` range indicate success. Codes in the `4xx` range indicate an error that failed given the information provided (e.g., a required parameter was omitted, a charge failed, etc.). KEYZY will respond with the following messages in case of errors in the endpoint request. - If the `app_id` or the `api_key` is wrong. ```json { "error": { "message": "You are not authorized!", "status_code": 401 } } ``` - If the SKU number is wrong. ```json { "error": { "message": "Sku does not exist!", "status_code": 404 } } ``` - If you have not generated, or if you do not have any available licenses remaining for the SKU. ```json { "error": { "message": "You do not have any free licenses for this sku. Please generate new licenses for this sku!", "status_code": 403 } } ``` - When validating, if the product code is wrong. ```json { "error": { "message": "Product does not exist!", "status_code": 404 } } ``` - When validating, if the serial number in the endpoint request is not correct, or is already registered. ```json { "error": { "message": "Serial does not exist or registered!", "status_code": 404 } } ``` --- ## Status Check Source: https://www.keyzy.io/docs/developers/rest-api/status-check/ Returns a 'Success' string to show the server works. ```bash GET https://api.keyzy.io/v2/status-check ``` ## Returns Keyzy responds with the following string ``` Success ``` --- ## Register Source: https://www.keyzy.io/docs/developers/rest-api/licenses-register/ Registers a new customer to a license. KEYZY can send an email to the customer with the license information. To do so, the settings for the connected SKU should be "true". ```bash POST https://api.keyzy.io/v2/licenses/register ``` ## Required parameters | Parameter | Type | Description | | --- | --- | --- | | app_id | string | An app_id that has "write" permission | | api_key | string | An api_key that has "write" permission | | sku_number | string | A sku_number | | name | string | Licensee's name | | email | string | Licensee's email address | ## Optional parameters | Parameter | Type | Description | | --- | --- | --- | | type | string | License's type. 'perpetual', 'subscription' or 'trial'. If omitted, the license inherits the SKU's type. | ## Required parameters if type is 'subscription' or 'trial' | Parameter | Type | Description | | --- | --- | --- | | start_at | int | License's start time for validation. Unix timestamp. | | end_at | int | License's end time for validation. Unix timestamp. | ## Returns Keyzy responds with a message containing a serial number if the request is correct. ```json { "message": { "serial": "1234-5678-89AB-CDEF-GHIJ" } } ``` --- ## Validate Source: https://www.keyzy.io/docs/developers/rest-api/licenses-validate/ Validates a license ```bash POST https://api.keyzy.io/v2/licenses/valid ``` ## Parameters | Parameter | Description | | --- | --- | | app_id | An app_id that has read permission | | api_key | An api_key that has read permission | | code | A product code | | serial | A license (serial number) to validate | | version | This is a constant to get the right result. It should be "2.0" | | host_id (optional) | An id to recognize the device | | device_tag (optional) | An operating system and bits information. Sample: "Windows 10__64bits" | ## Returns Keyzy responds with an object containing the status of the validation and some other useful information if the request is correct. ```json { "data": { "message": "valid", "licensee_name": "name of the licensee", "licensee_email": "licensee@email.com", "sku_number": "your-sku-number", "product_code": "the-product-code", "version_code": "version-code-string" } } ``` --- ## Encrypted File Source: https://www.keyzy.io/docs/developers/rest-api/licenses-encrypted-file/ Validates a license and responds with an encrypted license file. ```bash POST https://api.keyzy.io/v2/licenses/encrypted-file ``` ## Parameters | Parameter | Description | | --- | --- | | app_id | An app_id that has "read" permission | | api_key | An api_key that has "read" permission | | code | A product code | | serial | A license (serial number) to validate | | host_id (optional) | An id to recognize the device - It must be filled for the KEYZY C++ client library | | device_tag (optional) | An operating system and bits information. Sample: "Windows 10__64bits" | ## Returns Keyzy responds with an encrypted license file if the request is correct. --- ## Show License Source: https://www.keyzy.io/docs/developers/rest-api/licenses-show-license/ Shows a license's details. ```bash GET https://api.keyzy.io/v2/licenses/show-license/{serial-number}?app_id=XXXXXX&api_key=XXXXXXXXXXXXXXXXX ``` ## Variables | Variable | Description | | --- | --- | | serial-number | serial number | ## Parameters | Parameter | Description | | --- | --- | | app_id | An app_id that has read permission | | api_key | An api_key that has read permission | ## Returns ### Success ```json { "data": { "id": "int", "dealer_id": "int", "dealer_name": "string", "sku_id": "int", "sku_name": "string", "sku_number": "string", "sku_upgrade": "string", "sku_url": "string", "image_url": "string", "serial": "string", "definer": "string", "name": "string", "email": "string", "type": "perpetual|subscription|trial", "start_at": "unix timestamp", "end_at": "unix timestamp", "registered": "bool", "created_at": "timestamp", "updated_at": "timestamp" } } ``` ### Errors **You are not authorized** ```json { "error": { "message": "You are not authorized!", "status_code": 401 } } ``` **License does not exist!** ```json { "error": { "message": "License does not exist!", "status_code": 401 } } ``` --- ## License Products Source: https://www.keyzy.io/docs/developers/rest-api/licenses-products/ Returns a list of products that are related to a license. ```bash POST https://api.keyzy.io/v2/licenses/products ``` ## Parameters | Parameter | Description | | --- | --- | | app_id | An app_id that has write permission | | api_key | An api_key that has write permission | | serial | Serial number of the customer | ## Returns Keyzy responds with a message containing the product's data if the request is correct. ```json { "data": [ { "id": 435, "name": "kZip", "code": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "filename": "kZip.lic", "key": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "signature": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "signature_trial": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "active": true, "max_host_count": 3, "created_at": "2018-02-09 23:47:54", "updated_at": "2018-09-14 08:38:16" } ] } ``` --- ## Update SKU Source: https://www.keyzy.io/docs/developers/rest-api/licenses-update-sku/ Updates the connected SKU for a license. ```bash POST https://api.keyzy.io/v2/licenses/update-sku ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | | app_id | string | An app_id that has write permission | | api_key | string | An api_key that has write permission | | serial | string | A license (serial number) | | new_sku_number | string | License's new sku_number | | current_sku_number | string | License's current sku_number | ## Returns Keyzy responds with a message containing the status of the update if the request is correct. ```json { "message": "License successfully updated with the given new_sku_number." } ``` ## Notes - The new SKU's type will be overwritten to the license. For example; if the current license type is 'perpetual' and the new SKU's type is 'trial', after the update the license's type will be 'trial'. - If the new SKU's type is 'trial' or 'subscription', you may need to use [update-time](https://www.keyzy.io/docs/developers/rest-api/licenses-update-time/) endpoint separately. --- ## Update Time Source: https://www.keyzy.io/docs/developers/rest-api/licenses-update-time/ Updates a license's Start and End time for 'subscription' and 'trial' licenses. ```bash POST https://api.keyzy.io/v2/licenses/update-time ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | | app_id | string | An app_id that has write permission | | api_key | string | An api_key that has write permission | | serial | string | A license (serial number) | | start_at (optional) | int | Licensee's start time in unix timestamp | | end_at | int | Licensee's end time in unix timestamp | ## Returns Keyzy responds with a message containing the status of the update if the request is correct. ```json { "message": "OK" } ``` --- ## Upgrade Source: https://www.keyzy.io/docs/developers/rest-api/licenses-upgrade/ Upgrades a license by exchanging a **source** serial for a **target** serial: `current_serial` is the source, `upgrade_serial` is the target. On success the source license is deleted and the target license becomes available to activate — one license in, one license out. See [Upgrades](https://www.keyzy.io/docs/concepts/upgrades/) for which sources can be upgraded into which targets, and the [Upgrade Licenses tutorial](https://www.keyzy.io/docs/developers/tutorials/cpp-upgrade-licenses/) for a C++ walkthrough. > **Warning:** If it succeeds, deletes the current license. ```bash POST https://api.keyzy.io/v2/licenses/upgrade ``` ## Arguments | Parameter | Description | | --- | --- | | app_id | An app_id that has read permission | | api_key | An api_key that has read permission | | current_serial | Current license's serial number | | upgrade_serial | Upgrade license's serial number | ## Returns ### Success ```json { "message": "Upgrade license is ready to use." } ``` ### Errors **You are not authorized** ```json { "error": { "message": "You are not authorized!", "status_code": 401 } } ``` **Current license does not exist!** ```json { "error": { "message": "Current license does not exist!", "status_code": 404 } } ``` **Upgrade license does not exist!** ```json { "error": { "message": "Upgrade license does not exist!", "status_code": 404 } } ``` **Upgrade license does not match for upgrade with current license!** ```json { "error": { "message": "Upgrade license does not match for upgrade with current license!", "status_code": 422 } } ``` --- ## Register Products — Check Serial Source: https://www.keyzy.io/docs/developers/rest-api/licenses-register-products/ Step 1 of 2 in the Register Products flow: checks whether a serial is suitable for product registration and returns the license and product details, so your form can show the customer what they are about to register. A serial is suitable if it belongs to an offline-distributed (dealer) license that has not been registered yet. Nothing is written to the license. To complete the registration, continue with [Register Products — Submit Registration](https://www.keyzy.io/docs/developers/rest-api/licenses-register-products-edit/). ```bash GET https://api.keyzy.io/v2/register-products/{serial-number}?app_id=XXXXXX&api_key=XXXXXXXXXXXXXXXXX ``` ## Variables | Variable | Description | | --- | --- | | serial-number | serial number | ## Parameters | Parameter | Description | | --- | --- | | app_id | An app_id that has read permission | | api_key | An api_key that has read permission | ## Returns ### Success ```json { "data": [ { "id": "int", "dealer_id": "int", "dealer_name": "string", "sku_id": "int", "sku_name": "string", "sku_number": "string", "sku_url": "string", "image_url": "string", "serial": "string", "name": "string", "email": "string", "type": "perpetual|subscription|trial", "start_at": "unix timestamp", "end_at": "unix timestamp", "registered": "bool", "created_at": "timestamp", "updated_at": "timestamp" } ] } ``` ### Errors For general error format details, see [Errors](https://www.keyzy.io/docs/developers/rest-api/errors/). **You are not authorized** — the `app_id` or `api_key` is wrong. ```json { "error": { "message": "You are not authorized!", "status_code": 401 } } ``` **Serial not valid** — the serial number is too short. ```json { "error": { "message": "The serial number is not valid!", "status_code": 422 } } ``` **Serial not found** — the serial does not exist, is not assigned to a dealer, or is already registered. ```json { "error": { "message": "The license does not exist or is not assigned to a dealer or is already registered!", "status_code": 404 } } ``` --- ## Register Products — Submit Registration Source: https://www.keyzy.io/docs/developers/rest-api/licenses-register-products-edit/ Step 2 of 2 in the Register Products flow: registers an offline-distributed (dealer) license to a customer by setting their name and email. After this call the license is marked as registered and the customer appears as its owner. To check a serial and preview the product before registering, start with [Register Products — Check Serial](https://www.keyzy.io/docs/developers/rest-api/licenses-register-products/). ```bash PUT https://api.keyzy.io/v2/register-products/{serial-number} ``` ## Variables | Variable | Description | | --- | --- | | serial-number | serial number | ## Parameters | Parameter | Description | | --- | --- | | app_id | An app_id that has read permission | | api_key | An api_key that has read permission | | sku_number | SKU number | | name | Name of the user (optional) | | email | Email of the user (required) | ## Returns ### Success ```json { "message": "Serial successfully registered." } ``` ### Errors For general error format details, see [Errors](https://www.keyzy.io/docs/developers/rest-api/errors/). **You are not authorized** — the `app_id` or `api_key` is wrong. ```json { "error": { "message": "You are not authorized!", "status_code": 401 } } ``` **The email is missing or not valid** ```json { "error": { "message": { "email": ["The email field is required."] }, "status_code": 422 } } ``` **Serial not valid** — the serial number is too short. ```json { "error": { "message": "The serial number is not valid!", "status_code": 422 } } ``` **Serial not found** — the serial does not exist, is not assigned to a dealer, or is already registered. ```json { "error": { "message": "The license does not exist or is not assigned to a dealer or is already registered!", "status_code": 404 } } ``` --- ## Delete License Source: https://www.keyzy.io/docs/developers/rest-api/licenses-destroy-serial/ Deletes a license by its serial number. All activations belonging to that license are deleted along with it, so any device currently using the license stops validating. ```bash DELETE https://api.keyzy.io/v2/licenses/destroy-serial ``` > **Requires a write API key.** Never embed a write key in a distributable application — anyone who extracts it could delete your licenses. Call this endpoint from your backend, store, or automation tooling only. If you only want to free up a seat, delete the [activation](https://www.keyzy.io/docs/developers/rest-api/activations-delete/) instead and leave the license in place. ## Parameters | Parameter | Type | Description | | --- | --- | --- | | app_id | string | An app_id that has **write** permission | | api_key | string | An api_key that has **write** permission | | serial | string | The serial number of the license to delete | | type | string | The type of the license: `perpetual`, `subscription` or `trial` | The `type` you send must match the actual type of the license. This is a safety check: if they do not match, nothing is deleted and the request fails. It protects you from deleting the wrong record when a serial number is passed in from an external system such as a store or a CRM. ## Returns Keyzy responds with a message confirming the deletion if the request is correct. ```json { "message": "License successfully deleted." } ``` ## Errors **You are not authorized** — the `app_id` / `api_key` pair is wrong, or the key does not have write permission. ```json { "error": { "message": "You are not authorized!", "status_code": 401 } } ``` **License does not exist** — no license with that serial number belongs to your account. ```json { "error": { "message": "License does not exist!", "status_code": 404 } } ``` **License type mismatch** — the license exists, but its type is not the `type` you sent. Nothing is deleted. ```json { "error": { "message": "License type mismatch!", "status_code": 422 } } ``` ## Notes - The license is deleted together with its activations in a single call. You do not need to remove the activations first. - If you are using the [Zapier integration](https://www.keyzy.io/integrate/zapier/), the **Delete Perpetual** and **Delete Subscription** actions call this endpoint for you. --- ## Get Activations Source: https://www.keyzy.io/docs/developers/rest-api/activations-get/ Gets activations that connected to a serial number. ```bash GET https://api.keyzy.io/v2/activations/{serial-number}?app_id=XXXXXX&api_key=XXXXXXXXXXXXXXXXX ``` ## Parameters | Parameter | Description | | --- | --- | | serial-number | serial number | | app_id | An app_id that has read permission | | api_key | An api_key that has read permission | ## Returns ### Success ```json { "data": [ { "id": "int", "license_id": "int", "product_id": "int", "activated": "true/false", "host_id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "device_tag": "Windows 10__64bits", "created_at": "2018-11-11 13:23:31", "updated_at": "2018-11-13 16:59:31", "product_name": "name of the product", "serial": "XXXX-XXXX-XXXX-XXXX-XXXX", "sku_name": "name of the sku", "sku": "sku number" } ] } ``` ### Errors **You are not authorized** ```json { "error": { "message": "You are not authorized!", "status_code": 401 } } ``` **Activation does not exist** ```json { "error": { "message": "Activation does not exist!", "status_code": 404 } } ``` --- ## Delete Activation Source: https://www.keyzy.io/docs/developers/rest-api/activations-delete/ Deletes an activation. There are two ways to call this endpoint, depending on where the request comes from. Both use the same URL — the difference is the `keyzy-product-code` header. ```bash DELETE https://api.keyzy.io/v2/activations/{id} ``` ## Method 1 — Server-side, by activation ID Use this from your backend or admin tooling to remove **any** activation by its id (the `id` returned by [Get Activations](https://www.keyzy.io/docs/developers/rest-api/activations-get/)). > **Requires a write API key.** Never embed a write key in a distributable application — anyone who extracts it could modify or delete your licenses. For in-app deactivation, use [Method 2](#method-2--in-app-by-serial-number-and-device) instead. ### Parameters | Parameter | Description | | --- | --- | | id | id of the activation object | ### Arguments | Parameter | Description | | --- | --- | | app_id | An app_id that has **write** permission | | api_key | An api_key that has **write** permission | ## Method 2 — In-app, by serial number and device Use this inside a distributable application to let it deactivate **its own activation on the current device**. The request is scoped to a single serial number on a single device (`host_id`), so it can only ever remove that one activation. > **Works with a read API key.** This is the same call the KEYZY client libraries make internally, so you can bake a **read** key into your app and never ship write credentials. To select this method, send the `keyzy-product-code` header with your product code. When that header is present, the `{id}` segment of the URL is treated as the **serial number**. ### Headers | Header | Description | | --- | --- | | keyzy-product-code | Your product code | ### Parameters | Parameter | Description | | --- | --- | | serial | the serial number of the license (passed as `{id}` in the URL) | ### Arguments | Parameter | Description | | --- | --- | | app_id | An app_id that has **read** permission | | api_key | An api_key that has **read** permission | | host_id | The device whose activation should be removed (the same host_id used at activation / validation) | ## Returns ### Success ```json { "message": "Activation successfully deleted." } ``` ### Errors **You are not authorized** ```json { "error": { "message": "You are not authorized!", "status_code": 401 } } ``` **Activation does not exist** ```json { "error": { "message": "Activation does not exist!", "status_code": 404 } } ``` **Product does not exist** *(Method 2 — when the `keyzy-product-code` header does not match one of your products)* ```json { "error": { "message": "Product does not exist!", "status_code": 404 } } ``` **License does not exist** *(Method 2 — when the serial number is not found)* ```json { "error": { "message": "License does not exist!", "status_code": 404 } } ``` --- ## Update Activation Source: https://www.keyzy.io/docs/developers/rest-api/activations-put/ Updates an existing activation. Use this to **activate or deactivate** an activation by flipping its `activated` flag — for example, to remotely re-enable a device you previously turned off, or to disable one from your backend or admin tooling. ```bash PUT https://api.keyzy.io/v2/activations/{id} ``` The `{id}` is the activation's `id`, as returned by [Get Activations](https://www.keyzy.io/docs/developers/rest-api/activations-get/). > **Requires a write API key.** Never embed a write key in a distributable application — anyone who extracts it could modify or delete your licenses. ## Parameters | Parameter | Description | | --- | --- | | id | id of the activation object | ## Arguments | Parameter | Description | | --- | --- | | app_id | An app_id that has **write** permission | | api_key | An api_key that has **write** permission | | activated | `true` to activate the activation, `false` to deactivate it | ## Returns ### Success ```json { "message": "Activation successfully updated." } ``` ### Errors **You are not authorized** ```json { "error": { "message": "You are not authorized!", "status_code": 401 } } ``` **Activation does not exist** ```json { "error": { "message": "Activation does not exist!", "status_code": 404 } } ``` **Missing or invalid `activated`** *(the `activated` argument is required and must be a boolean)* ```json { "error": { "message": { "activated": [ "The activated field is required." ] }, "status_code": 422 } } ``` --- ## Update Activation (Deprecated) Source: https://www.keyzy.io/docs/developers/rest-api/activations-put-deprecated/ > **Deprecated:** This endpoint is deprecated. Please use the [new update endpoint](https://www.keyzy.io/docs/developers/rest-api/activations-put/) instead. Updates an activation. ```bash PUT https://api.keyzy.io/v2/activations/update-api/{id} ``` ## Parameters | Parameter | Description | | --- | --- | | id | id of the activation object | ## Arguments | Parameter | Description | | --- | --- | | app_id | An app_id that has write permission | | api_key | An api_key that has write permission | | activated | true / false | ## Returns ### Success ```json { "message": "Activation successfully updated." } ``` ### Errors **You are not authorized** ```json { "error": { "message": "You are not authorized!", "status_code": 401 } } ``` **Activation does not exist** ```json { "error": { "message": "Activation does not exist!", "status_code": 404 } } ``` --- ## Delete Activation (Deprecated) Source: https://www.keyzy.io/docs/developers/rest-api/activations-delete-deprecated/ > **Deprecated:** This endpoint is deprecated. Please use the [new delete endpoint](https://www.keyzy.io/docs/developers/rest-api/activations-delete/) instead. Deletes an activation. ```bash DELETE https://api.keyzy.io/v2/activations/destroy-api/{id} ``` ## Parameters | Parameter | Description | | --- | --- | | id | id of the activation object | ## Arguments | Parameter | Description | | --- | --- | | app_id | An app_id that has write permission | | api_key | An api_key that has write permission | ## Returns ### Success ```json { "message": "Activation successfully deleted." } ``` ### Errors **You are not authorized** ```json { "error": { "message": "You are not authorized!", "status_code": 401 } } ``` **Activation does not exist** ```json { "error": { "message": "Activation does not exist!", "status_code": 404 } } ``` --- ## Install the Plugin Source: https://www.keyzy.io/docs/developers/integrations/woocommerce/install/ The KEYZY WooCommerce Plugin connects your WooCommerce store to KEYZY, depositing and delivering licenses automatically on each order. To start with, please download the [keyzywc.zip](https://www.keyzy.io/docs/developers/downloads/woocommerce-plugin/) file first. ## Install the WooCommerce plugin The installation process is the same as any other Wordpress plugin. - Login to your WooCommerce store as admin - Go to the "Admin Dashboard" - Click "Add New menu item" under the "Plugins Menu" - Click "Upload Plugin" - Click "Choose File" and select the "keyzywc.zip" file - After the installation finishes, activate the plugin ## Settings ### Add the "AppId" and the "ApiKey" to the plugin settings - Go to Keyzy's dashboard - Click the "App Keys" menu item - If you do not have a "Write App Key" pair with "Write Permissions", you can create one with the following steps: - Click "Add New App Key" - Change permissions to "Write" - Click "Add" - Copy the "AppId" and "ApiKey" information - Go to the WordPress Admin Panel sidebar - Click **Settings → Keyzy Settings** - Paste the "AppId" and "ApiKey" in their respective boxes - Click "Save Changes" ### Other Plugin Settings **Show Download Link**: Enable this option to allow users to download their license files from the [keyzy-downloads] page. **Show HostID Input Field**: Enable this option if you use a fully offline activation schema. Users will need to copy and paste their HostID into this field. **Show Manageable Activations to Users**: Enable this option to allow users to delete their activations from the KEYZY system for Online and Semi-Online activation schemas. For Offline activation schemas, users can still delete activations, but the deletion is not reflected on the client side. Similarly, if there is no internet connection, deletions for Semi-Online activations will not be reflected on the client side. **Disable Register Product Notification:** Enable this option to prevent WooCommerce from sending order emails when users register a product purchased from a dealer using the Register Product function. ## Add The Shortcode to A Page After the installation of KeyzyWc, you may add "keyzy download" shortcode to any page of your WooCommerce site. Open a page and add `[keyzy-downloads]` shortcode. ## Customizing the Downloads Page Appearance The `[keyzy-downloads]` shortcode output uses CSS classes so you can easily customize the appearance to match your theme. **CSS classes:** - `.keyzy-sku-block` — Wrapper for each license/SKU (separated by a 2px border) - `.keyzy-product-block` — Wrapper for each product within an SKU (separated by a 1px border) - `.keyzy-activation-row` — Each activation entry under a product **Example overrides:** ```css /* Remove borders between products */ .keyzy-product-block { border-top: none; } /* Custom SKU separator */ .keyzy-sku-block { border-top: 3px solid #333; margin-top: 30px; } /* Increase activation indent */ .keyzy-activation-row { margin-left: 20px; } ``` No changes needed on your end — everything works out of the box with sensible defaults. ## Important Notes Make sure your WooCommerce products are marked as **Virtual** (and optionally **Downloadable**). WooCommerce automatically completes orders for virtual products after payment. If a product is not marked as Virtual, the order stays in "Processing" status and the KEYZY plugin will not assign licenses. Make sure you have created licenses in KEYZY for the SKU before testing. When a WooCommerce order comes in, the plugin deposits one of the available licenses to the customer — if there are no available licenses, nothing will be deposited. The Product's *SKU* on WooCommerce should be the same as the *SKU Number* in KEYZY SKU Page. ![KEYZY SKU Number](https://www.keyzy.io/docs/woocommerce-sku-number.png) You should also apply the following options on WooCommerce: - Uncheck: "Allow customers to place orders without an account", under WooCommerce Settings -> Accounts & Privacy - Check: "Allow customers to create an account during checkout", under WooCommerce Settings -> Accounts & Privacy ## How to Debug KEYZYWc uses the standard WordPress error log file for logging. To enable logging in WordPress, add the following settings to your `wp-config.php` file: ```php ini_set( 'log_errors', 1 ); ini_set( 'error_log', '/path/to/debug.log' ); ``` --- ## Register Your Product Source: https://www.keyzy.io/docs/developers/integrations/woocommerce/register-product/ The "Register Your Product" feature lets end users who bought your software through a [dealer](https://www.keyzy.io/docs/getting-started/distributing-licenses/) register their serial number on your WooCommerce store. This gives them access to downloads and order history on your site. ## Prerequisites - The serial number must belong to a **dealer license** (offline-distributed). Regular licenses registered through the store or API are not eligible. - The WooCommerce product must have the same SKU number as the KEYZY SKU linked to the license. The plugin matches by SKU number to find the correct product. ## Inserting the Shortcode Add the following shortcode to any page on your WooCommerce store: ``` [keyzy-register-product] ``` ## How It Works 1. The customer signs in to your WooCommerce store. 2. They enter their dealer-provided serial number into the form and click **Register**. 3. The plugin verifies the serial against the KEYZY API. 4. On success, the plugin creates a **zero-total order** (with a 100% discount) on your WooCommerce store and marks it as completed. This makes the product appear on the customer's **Downloads** page. 5. The license is marked as registered on KEYZY with the customer's name and email. Register Your Product Form ## Notification Email By default, WooCommerce sends an order completion email when the zero-total order is created. If you want to disable this notification, go to **Settings > Keyzy Settings** in your WordPress admin and enable **Disable Register Product Notification**. ## Error Messages | Error | Cause | |---|---| | The serial number is required! | The input field is empty. | | Please check the serial number field! | The serial number is too short. | | Wrong serial number! | The serial does not exist, is not a dealer license, or is already registered. | | You are not authorized! | The app_id or api_key in Keyzy Settings is incorrect. | | Product not found! | No WooCommerce product matches the SKU number of the license. Make sure your WooCommerce product SKU matches the KEYZY SKU number. | --- ## Subscriptions Source: https://www.keyzy.io/docs/developers/integrations/woocommerce/subscription/ This guide connects WooCommerce Subscriptions to KEYZY via webhooks, so licenses are created and updated automatically as subscriptions renew. ## Prerequisites This integration requires the **[WooCommerce Subscriptions](https://woocommerce.com/products/woocommerce-subscriptions/)** plugin to be installed and active on your WooCommerce store. WooCommerce Subscriptions is a paid plugin by Woo that adds subscription functionality, including the "Subscription Created" and "Subscription Updated" webhook topics used in this guide. Without WooCommerce Subscriptions, these webhook topics will not be available in your WooCommerce settings. ## Set WooCommerce Settings We can create two webhooks for now. One webhook is for creating and another one is for updating. The first one is "subscription created". The "subscription created" is called when your customer starts a successful subscription. The second one is "subscription updated". The "subscription updated" is called when the subscription is renewed and deleted. First, go to WooCommerce Settings --> Advanced --> Webhooks Click to "Add webhook" button for Subscription Created Topic ## Subscription Created Topic Parameters - **Name:** any name you like (e.g. "keyzy-subscription-create") - **Status:** Active - **Topic:** Subscription Created - **Delivery URL:** `https://api.keyzy.io/v2/webhooks/woocommerce-subscription` - **Secret:** Please follow "Create a New Appkey Pair for Secret" section - **API Version:** WP REST API Integration v1 Now, we've just created our first webhook for the "subscription created" topic. We need to create another one for "subscription updated". To do that, click to "Add webhook" button again for the "subscription updated" topic. ## Subscription Updated Topic Parameters - **Name:** any name you like (e.g. "keyzy-subscription-update") - **Status:** Active - **Topic:** Subscription Updated - **Delivery URL:** `https://api.keyzy.io/v2/webhooks/woocommerce-subscription` - **Secret:** Please follow "Create a New Appkey Pair for Secret" section - **API Version:** WP REST API Integration v1 ## Create a New Appkey Pair for Secret - Create a new appkey pair on https://app.keyzy.io/app-keys - The label should be your base e-commerce base name (e.g. `https://www.your-domain.com/`) - Permission: Write - Is App Key Active?: True - Copy only API KEY info to WooCommerce's Secret field - You only need one API KEY for all webhooks. Create one appkey pair and use the API KEY value for all webhooks. ## Bear In Mind - The product's SKU number (in WooCommerce, it's just SKU) and KEYZY's SKU number should be the same - Be aware that you need to create a subscription product on WooCommerce. ## Troubleshooting ### Empty webhook payload If your webhooks are firing but KEYZY is not receiving any data, the webhook payload body is likely empty. This is a known issue when **High-Performance Order Storage (HPOS)** is enabled in WooCommerce. **Fix:** Go to **WooCommerce → Settings → Advanced → Features** and enable **High-Performance Order Storage compatibility mode**. This ensures that subscription webhook payloads are populated correctly. ### General tips - Make sure that the webhook is active or not, if it gets errors, WooCommerce can turn the webhook automatically off. - There is a lag between the order time and the webhook trigger time. You need to wait for a short time to see the subscription information on KEYZY dashboard. ## How to debug You may need to look at the responses from KEYZY service. To do that, please look at the logs under **WooCommerce --> Status --> Logs**. You'll see files starting with `webhooks-delivery-YYYY-MM-DD--UNIQUE-ID` (e.g. webhooks-delivery-2021-12-05-cf5ea08f2e6045ad6d889249b3ef8fa3.log) --- ## Upgrade Your Product Source: https://www.keyzy.io/docs/developers/integrations/woocommerce/upgrade/ You can use the "Upgrade" feature of the KEYZY WooCommerce Plugin to upgrade a license for your customers. ## Inserting "Upgrade" Shortcode With the following KEYZY WooCommerce plugin shortcode, you can display the "Upgrade" form on any page of your website. ``` [keyzy-upgrade] ``` ## How Your Customers Use That Form They need to be signed in to your WooCommerce store to be able to see the form. They'll see two text boxes. After they enter the serial numbers into the boxes and press the submit button, their upgrade process will finish. ![Upgrade Form](https://www.keyzy.io/docs/woocommerce-upgrade-form.png) --- ## FastSpring Integration Source: https://www.keyzy.io/docs/developers/integrations/fastspring/ ## Install The Plugin - Download the Woocommerce FastSpring Plugin as a Zip file: github.com/cyberwombat/woocommerce-fastspring-payment-gateway - Upload it to your store and activate it ## General Settings - Go you your WooCommerce Settings page, click Checkout tab and click FastSpring link - Check *Enable FastSpring payment gateway* - If you want to test it first (recommended), check *Enable Test Mode* - Use only Popup link for Storefront input **How to get Popup link? (ONLY USE POPUP STOREFRONTS)** - Go to your FastSpring dashboard - Click to *Storefronts* link - Click *Popup Storefronts* tab - Click *No whitelisted* websites - Enter your store's full URL (e.g. `https://www.yourstore.com`) and click *SAVE* - Click *PLACE ON YOUR WEBSITE* link - In the Script, copy the value of *data-storefront* which is your Popup link (e.g. `yourstorename.fastspring.com/yourstorename-popup`) - Go back to your WooCommerce store Checkout FastSpring settings page and paste the link to *Storefront* input ## Store Build Library Settings - Create a Private and Public key pair: ```bash openssl genrsa -out privatekey.pem 2048 openssl req -new -key privatekey.pem -x509 -days 3650 -out publiccert.pem ``` - Go to your FastSpring dashboard - Click *Integrations* and *Store Build Library* - Click *Choose File* button under *File Upload* section and show your *publiccert.pem* file - Click Save - Copy your access key under ACCESS KEY section - Go back to your WooCommerce store - Paste your access key to Access Key input - Open your *privatekey.pem* file in a text editor - Copy all text included "-----BEGIN RSA PRIVATE KEY-----" and "-----END RSA PRIVATE KEY-----" parts - Paste the text to *Private Key* input ## Webhook Settings - Copy *Webhook* Secret - Click *Integrations* and *Webhooks* - Click *ADD WEBHOOK URL* link - Go to your WooCommerce store Checkout FastSpring settings page and copy your webhook URL under *Webhook Method Instructions* section - Go back to your FastSpring dashboard and paste it to URL section - Go to your WooCommerce store Checkout FastSpring settings page again and copy *Webhook Secret* - Go back to your FastSpring dashboard and paste it to *HMAC SHA256 Secret* section - Check order.completed, order.canceled, order.failed checkboxes - Click *Add* ## API Credential Settings - Click *Integrations* and *API Credentials* - Create API Credentials - Copy and Paste Username and Password respectively to your WooCommerce Checkout FastSpring Settings page's *API Username* and *API Password* inputs - Don't forget to uncheck *Enable Test Mode* after your tests are finished ## Save All Settings Click Save Changes ![FastSpring Settings](https://www.keyzy.io/docs/fastspring-settings.jpg) --- ## Upgrades Source: https://www.keyzy.io/docs/concepts/upgrades/ An upgrade moves a customer from one SKU to another — for example *Standard → Gold*, or *V1 → V2*. This page explains how upgrades work, independently of any specific language or store integration. For implementation details, see the [C++ Upgrade Licenses tutorial](https://www.keyzy.io/docs/developers/tutorials/cpp-upgrade-licenses/) or the [WooCommerce upgrade integration](https://www.keyzy.io/docs/developers/integrations/woocommerce/upgrade/). ## The two licenses involved Every upgrade involves two serials: - The **source** — the customer's current license. - The **target** — the upgrade license they move to. ## How the match works - When you create the upgrade (target) license, you mark it as an upgrade license and choose which **source SKU(s)** it accepts. - KEYZY validates the upgrade by **SKU identity**: it checks whether the source license's SKU is one of the accepted sources. It does **not** compare the individual products inside two SKUs. - An upgrade can accept **several source SKUs at once**. This is "any one of these sources" (OR) — a holder of any accepted source SKU can use the upgrade, and you do not need a separate upgrade definition per source. If the source license's SKU is not an accepted source, the upgrade is rejected (an "upgrade does not match" result). ## One license in, one license out An upgrade is strictly **one license in, one license out**. On success the server deletes the source license and makes the target available to activate. After the upgrade succeeds on the server, you still activate the target serial as usual. ## Related - [Bundles](https://www.keyzy.io/docs/concepts/bundles/) — modeling bundles and completing them with upgrades - [C++ Upgrade Licenses](https://www.keyzy.io/docs/developers/tutorials/cpp-upgrade-licenses/) - [WooCommerce Upgrade](https://www.keyzy.io/docs/developers/integrations/woocommerce/upgrade/) --- ## Bundles Source: https://www.keyzy.io/docs/concepts/bundles/ In KEYZY a bundle is not a separate type of object: it is a [SKU](https://www.keyzy.io/docs/dashboard/skus/) with more than one product attached. Everything that is true of a SKU is true of a bundle — the only difference is how many products are inside. ## Why a bundle lives in the license layer Because a bundle is a single SKU, the customer receives **one serial** that activates every product in it. That gives you: - One serial for the customer, instead of several keys to manage. - One catalog item for dealers to stock and distribute, consuming a single license. - A clean upgrade path between bundles. For the reasoning behind keeping bundles in the license layer rather than only in the cart, see the guide [Bundles That Belong in Your License Layer, Not Your Cart](https://www.keyzy.io/guides/bundles-license-layer-not-cart/). ## Completing or upgrading a bundle Bundles combine naturally with [upgrades](https://www.keyzy.io/docs/concepts/upgrades/). For example, define **Bundle SKU Y** as a SKU containing Product A, Product B and Product C, and **Bundle SKU Z** as a SKU containing Product A, Product B, Product C and Product D: - Create the Bundle SKU Z upgrade with **Bundle SKU Y** as its accepted source. *Bundle SKU Y → Bundle SKU Z* is then fully automatic, a single clean serial throughout, and ownership is verified intrinsically: only a holder of a Bundle SKU Y license can use it. - Routing through the bundle in steps keeps pricing fair. To reach Bundle SKU Z a customer must first hold Bundle SKU Y, so nobody can jump from a single product straight to the full bundle for the price of "adding Product D". An upgrade always consumes exactly one license, so it cannot merge several separate licenses into one. If a customer already holds separate single-product licenses and you want to move them onto a bundle, do it as a **one-time migration you run yourself** — you hold the sales records that prove what they own. Issue the bundle license and retire their old separate licenses. ## Related - [SKUs](https://www.keyzy.io/docs/dashboard/skus/) — a bundle is a multi-product SKU - [Upgrades](https://www.keyzy.io/docs/concepts/upgrades/) — how upgrades work - [Bundles That Belong in Your License Layer, Not Your Cart](https://www.keyzy.io/guides/bundles-license-layer-not-cart/) --- ## Versions (editions) Source: https://www.keyzy.io/docs/concepts/versions/ A version — also called an **edition** — is a stable label that tells your application which feature set to unlock. A single product can ship as *Standard*, *Gold* and *Platinum* editions from the same codebase: each carries a different version, and your code switches on it. Every product has a default **"Full"** version (code `full`) until you define more. A version is two things: a human-readable **label** (for example *Gold*) and a short, stable **code** (for example `gold`). Your application never reads the label — it reads the code. ## A version is attached through the SKU A product can be assigned several versions. Which one a customer actually receives is decided **where the product meets the [SKU](https://www.keyzy.io/docs/dashboard/skus/)**: when you put a product into a SKU, you pick the version it ships with there. This means the same product can carry a **different edition in different SKUs**: - *Photo Editor* inside the **Standard SKU** ships with version `standard`. - *Photo Editor* inside the **Gold SKU** ships with version `gold`. The customer activates one serial, KEYZY resolves the SKU → product → version, and the license your application receives already contains the right edition code. There is nothing extra to configure on the device. ## Why a version code, not the SKU name Your SKU number and name are catalog data: you rename them, reprice them, retire and replace them as your offering changes. If your application branched on the SKU, every such change would risk breaking feature gating in shipped binaries. A version **code is the stable contract** between your catalog and your code. You commit to `gold` once, and your application can trust it unconditionally — regardless of how the SKU around it is renamed or restructured later. Editions decouple "what your code checks" from "how you package and sell." This pays off most as your catalog grows, because **one version can live in many SKUs**. The same `gold` edition might back a dozen SKUs — different prices, regions, bundles, campaigns, renewals — yet your code still checks a single code. Without editions, your application would have to know every SKU name that counts as "gold", and keep that list in sync as SKUs are added, renamed and retired. That is manageable for one SKU and a maintenance nightmare across many. An edition collapses that whole list back into one stable code. ## Reading the edition in your application After a successful activation or validation, the edition code is available from the license. In the C++ SDK: ```cpp std::string version = pValidator->getVersion(); // e.g. "gold" if (version == "gold") { // unlock Gold features } ``` The same code is returned in the REST API as `version_code` on the validate response, so server-side and online flows can branch on it too. Because the code is fixed, the same binary handles every edition — you ship once and let the license decide what to turn on. ## Related - [Versions (dashboard)](https://www.keyzy.io/docs/dashboard/versions/) — creating and editing versions in the UI - [SKUs](https://www.keyzy.io/docs/dashboard/skus/) — a version is attached where a product meets a SKU - [Products](https://www.keyzy.io/docs/dashboard/products/) — assigning versions to a product - [Upgrades](https://www.keyzy.io/docs/concepts/upgrades/) — moving a customer from one edition to another --- ## Setting Up Your Product Source: https://www.keyzy.io/docs/getting-started/setting-up-your-product/ Before you can sell or distribute licenses, you need to set up three things in the KEYZY dashboard: a **Product**, an **SKU**, and **Licenses**. ## Add a Product A product represents your software application. 1. Go to the [Products](https://app.keyzy.io/products) page 2. Click **Add New Product** 3. **Name** — give your product a recognizable name 4. **Is Product Active?** — set to active so licenses can be validated against it 5. **How many devices?** — the maximum number of devices a single license can be activated on. For example, set this to 3 if you want each customer to use the software on up to 3 machines. Add Product ## Add an SKU (Stock Keeping Unit) An SKU defines a specific version or tier of your product — for example, "Pro Annual" or "Basic Perpetual". Each SKU has its own license type, pricing tier, and settings. 1. Go to the [SKU](https://app.keyzy.io/skus) page 2. Click **Add New SKU** 3. **Name** — include the product name and tier (e.g. "ProductA Pro Perpetual", "ProductA Starter Subscription") 4. **SKU Number** — a unique identifier you'll use in API calls and your store integration. Cannot contain spaces. 5. **License Type** — choose one: - **Perpetual** — license never expires - **Subscription** — license expires after a set period, requires renewal - **Trial** — time-limited evaluation license 6. **Offline License Life** — how long a locally cached license remains valid before the application needs to contact the server again. This applies to semi-online activation. Set the value in days. 7. **Is SKU Active?** — set to active 8. **This is an upgrade SKU** — enable this if licenses under this SKU are meant to be used as upgrade targets (e.g. upgrading from Basic to Pro) 9. **Enable Auto License Generation** — when enabled, KEYZY automatically generates new licenses when stock runs low, so you never run out during sales Add SKU ### Associate Products to Your SKU After creating the SKU, you need to link at least one product version to it: 1. Go back to the [SKU](https://app.keyzy.io/skus) list 2. Click **Manage Products** on your SKU 3. Select the product version you created earlier ## Generate Licenses Once you have a product and an SKU, you can generate licenses. 1. Go to the [Licenses](https://app.keyzy.io/licenses) page 2. Click **Add Licenses** 3. Select the **SKU** you want to generate licenses for 4. Optionally select a **Dealer** if you sell through a third party 5. Choose **how many licenses** to generate 6. Click **Add** Add Licenses Generated licenses are ready to be distributed. See [Distributing Licenses](https://www.keyzy.io/docs/getting-started/distributing-licenses/) for the different distribution methods available. ## Next Steps - [Setting Up Your Product for Sale](https://www.keyzy.io/docs/getting-started/setting-up-for-sale/) — add App Keys and Dealers - [Distributing Licenses](https://www.keyzy.io/docs/getting-started/distributing-licenses/) — deliver licenses to your customers --- ## Setting Up Your Product for Sale Source: https://www.keyzy.io/docs/getting-started/setting-up-for-sale/ After [setting up your product](https://www.keyzy.io/docs/getting-started/setting-up-your-product/), you need to create an App Key so your store can communicate with KEYZY. If you sell through third parties, you'll also need to add Dealers. ## Add an App Key An App Key is an API credential that allows external systems to communicate with the KEYZY API. Both your e-commerce store and the C++ Client Library embedded in your application use App Keys to authenticate with KEYZY. 1. Go to the [App Keys](https://app.keyzy.io/appkeys) page 2. Click **Add New App Key** 3. **Label** — a name to identify where this key is used (e.g. your store URL) 4. **Permissions** — choose the access level: - **Read** — can only query and validate license data (used by the C++ Client Library and for reporting) - **Write** — can register licenses, manage activations, and perform all operations (use this for your e-commerce store) 5. **Is App Key Active?** — set to active 6. Click **Add** Add App Key After creating the App Key, copy it and use it in your store integration. For example, the [WooCommerce plugin](https://www.keyzy.io/docs/developers/integrations/woocommerce/install/) requires the App Key during setup. > **Keep your App Key secure.** It provides API access to your account. Do not share it publicly or commit it to version control. ## Add a Dealer (Optional) Dealers are third parties who distribute your licenses on your behalf — for example, a reseller or a retail partner. When you generate licenses for a dealer, those licenses are allocated to them for distribution. 1. Go to the [Dealers](https://app.keyzy.io/dealers) page 2. Click **Add New Dealer** 3. **Dealer Name** — the name of the third party (e.g. "Sweetwater") 4. Click **Add** Add Dealer Once a dealer is created, you can select it when [generating licenses](https://www.keyzy.io/docs/getting-started/setting-up-your-product/#generate-licenses). See [Distributing Licenses](https://www.keyzy.io/docs/getting-started/distributing-licenses/) for more on how dealer distribution works. ## Next Steps - [Distributing Licenses](https://www.keyzy.io/docs/getting-started/distributing-licenses/) — deliver licenses to your customers - [Offline Licensing with WooCommerce](https://www.keyzy.io/docs/getting-started/offline-licensing-woocommerce/) — set up offline activation through your store --- ## Distributing Licenses Source: https://www.keyzy.io/docs/getting-started/distributing-licenses/ After you generate licenses on the [Licenses](https://app.keyzy.io/licenses) page, you need to deliver them to your customers. KEYZY supports several distribution methods. ## WooCommerce Plugin The most common method. The [KEYZY WooCommerce plugin](https://www.keyzy.io/docs/developers/integrations/woocommerce/install/) handles everything automatically — when a customer completes a purchase, the plugin registers a license via the API and displays the serial number on the order confirmation page. The plugin also supports offline licensing. See [Offline Licensing with WooCommerce](https://www.keyzy.io/docs/getting-started/offline-licensing-woocommerce/) for setup details. ## API Based Distribution If you use a custom store or a different e-commerce platform, you can call the [Register License API](https://www.keyzy.io/docs/developers/rest-api/licenses-register/) from your backend after a successful purchase. The API returns a serial number that you can display to the customer or send via email. > The Register endpoint automatically marks the license as distributed — no manual step needed. ## Automatic Email Distribution If you don't want to implement showing the serial number yourself, KEYZY can email it directly to the customer. To enable this: 1. Go to the [SKU](https://app.keyzy.io/skus) page in the dashboard 2. Open the SKU settings 3. Enable the automatic email option When a license is registered through the API, KEYZY sends the serial number to the customer's email address automatically. ## Manual Distribution You can also distribute licenses manually — for example, by sending the serial number via email or a support ticket. 1. Go to the [Licenses](https://app.keyzy.io/licenses) page 2. Find the license you want to distribute 3. Copy the serial number and send it to your customer 4. Set the **Registered** field to **True** to mark the license as distributed > If the license belongs to a dealer, the Registered field cannot be set manually. It is automatically set to True when the license is registered through the API. ## Offline Distribution (Dealers) Offline distribution is for licenses sold through third-party dealers. You generate a batch of licenses and hand them to the dealer — from that point, the distribution happens outside of KEYZY. You won't know when or to whom the dealer sells each license. When an end user activates an offline distributed license, the [Register Products API](https://www.keyzy.io/docs/developers/rest-api/licenses-register-products-edit/) can be used to record the owner's name and email — but the sale date and circumstances remain unknown to KEYZY. See [Setting Up Your Product for Sale](https://www.keyzy.io/docs/getting-started/setting-up-for-sale/) for how to add dealers to your account. --- ## Offline Licensing with WooCommerce Source: https://www.keyzy.io/docs/getting-started/offline-licensing-woocommerce/ Offline licensing allows your customers to activate and use your software on a device without an internet connection. The license file is generated through your WooCommerce store and loaded into your application locally. This guide covers the full flow — from your store settings to the end user's experience. ## How It Works 1. Your application displays the device's **Host ID** to the user 2. The user purchases a license from your WooCommerce store 3. On the order downloads page, the user enters their Host ID 4. The store generates an encrypted license file for that specific device 5. The user downloads the file and loads it into your application 6. Your application validates the license file locally — no internet needed ## Configure Your WooCommerce Store In the KEYZY WooCommerce plugin settings, enable two options: 1. Go to **WooCommerce > Settings > KEYZY** (or the KeyzyWc settings page) 2. Enable **"Show Download Link"** — this lets the user download the encrypted license file 3. Enable **"Show HostID Input Field"** — this adds an input where the user can paste their Host ID Without these options enabled, the user won't see the fields needed for offline activation. ## Display the Host ID in Your Application Your application needs to show the user their device's unique Host ID. Use the `getHostIdHash()` function from the KEYZY C++ Client Library: ```cpp std::string hostId = pValidator->getHostIdHash(); // Display this to the user — e.g. in a dialog, or copy it to the clipboard ``` The Host ID is a hash that uniquely identifies the device. The user copies this value and enters it in your WooCommerce store when downloading the license file. > **Important:** The Host ID must be copied exactly. An incorrect Host ID will produce a license file that won't work on the device. ## The User's Experience After purchasing a license from your store: 1. The user goes to their order's downloads page 2. They paste the Host ID from your application into the input field 3. They click download — the store generates an encrypted license file tied to that device 4. The user saves the file and provides it to your application (e.g. via a file browser dialog) ## Activate the License File Once the user has the license file, your application needs to load and validate it. See the [Offline Activation](https://www.keyzy.io/docs/developers/tutorials/cpp-offline-activation/) tutorial for the full implementation — covering activation, validation, offline license life, and deactivation. ## Tips - The encryption key in your `ProductData` is required for offline activation — you can find it on the [Products](https://app.keyzy.io/products) page in the dashboard - Each license file is tied to a specific device via the Host ID — it cannot be used on a different machine - If a user needs to move their license to a new device, they need to deactivate on the old device and generate a new license file with the new device's Host ID --- ## Dashboard Source: https://www.keyzy.io/docs/dashboard/overview/ The dashboard is the main page in KEYZY, which is displayed first after you log in. Here you can see the number of: - Products - SKUs - Dealers - Licenses ![Dashboard](https://www.keyzy.io/dashboard.webp) --- ## Versions Source: https://www.keyzy.io/docs/dashboard/versions/ Versions help you to create different versions of your products. Each version has a set of features and you can customize your software with it. For example, you may have Standard Version, Gold Version, Platinum Version and each version acts differently. ## Adding a New Version By default, all existing products have a "Full" version. Whenever you create a new product it will be assigned to the "Full" version. Follow these steps to edit this version or add new ones: 1. To go to the version page, click the versions icon from the menu bar 2. To create a new version, click the **"Add new version"** button. To edit an existing version, click on your version name. 3. This will open a pop-up box where you can modify: - Version label - Version code The search bar allows you to search versions by any term in the version columns, by label, or by code. ![Versions Page](https://www.keyzy.io/dashboard-versions.webp) --- ## Products Source: https://www.keyzy.io/docs/dashboard/products/ Products are software items you distribute or sell. ## Adding a New Product 1. To go to the product page, click products icon from the menu bar 2. To create a new product, click the **"Add new product"** button. To edit an existing product, click on your product name. 3. This will open a pop-up box where you can modify: - The product name - The status of the product (active or inactive) - The number of devices the product can be activated on using a single license key (you can choose 1-10 devices or unlimited devices per license) ![Products Page](https://www.keyzy.io/dashboard-products.webp) ## Managing Versions Every existing product needs to have at least one version assigned to the product. Each time you create a new product, it gets assigned to "Full" version by default. To manage versions of a product, click the **"Manage Versions"** button. Then you can assign product versions you already created on the Versions section. Manage Versions The search bar allows you to search products by any term in the product columns, by name, by version, by code or by cryption key. --- ## SKUs Source: https://www.keyzy.io/docs/dashboard/skus/ When a customer purchases your product they purchase an SKU (Stock Keeping Unit). Only one version of a product can be assigned to an SKU, and each SKU receives its own license keys. A single SKU can contain one or several products. This means that you can activate every product in the SKU with a single license key. In KEYZY a **bundle** is not a separate kind of object — it is simply a SKU with more than one product attached. A SKU with a single product is a single-product SKU; a SKU with several products is a bundle. ## Adding a New SKU 1. To go to the SKU page, click the **SKUs** icon in the menu bar 2. To create a new SKU, click the **"Add new SKU"** button. To edit an existing SKU, click on its name. 3. This will open a pop-up box where you can modify: - The SKU name - The SKU number - **Offline License Life:** Specifies how many days the offline license will be valid on your customer's device. If you set it to 0, there is no time restriction and your customer can use it forever. - **License Type:** Perpetual / Subscription / Trial. Can't be changed later. - Whether the SKU is active or not ![SKUs Page](https://www.keyzy.io/dashboard-skus.webp) ## SKU Details Clicking on the name of your SKU will open a new pop-up box where you can modify additional options: - You can select if you would like to send the serial number automatically to your client once a license has been activated (select True under the question "Should we send serial number...") - You can add a message to send to your client together with the serial number (fill in the field "Notes for email") - Additionally, you can modify the name of the SKU, its number and its status ## Managing Products Every existing SKU needs to have products assigned to it. The connection is made between an SKU and a version of a product. Click the **"Manage Products"** button to select which of your existing products will be bundled under the SKU. The search bar allows you to search SKUs by any term in the SKU columns, by SKU name, by products or by SKU number. --- ## Licenses Source: https://www.keyzy.io/docs/dashboard/licenses/ License keys are used to register your product. Each license key is related to an SKU. One license key can be used to activate one or several products. A license key can be used to activate a product online (through your own sales website), or offline (through a dealer). ## Adding New Licenses 1. To go to the License page, click the **Licenses** icon in the menu bar. In the main license window you can see the SKU to which the licenses are assigned, the individual serial numbers for each SKU, the status of the serial number, the dealer name (if applicable), the licensee, their email address and the date the license key was created. 2. To create a new license, click the **"Add Licenses"** button. 3. This will open a pop-up box where you can select: - The SKU for which you are generating license numbers - The dealer (if applicable) - The number of license keys for the selected SKU - If they are upgrade licenses or not ![Licenses Page](https://www.keyzy.io/dashboard-licenses.webp) KEYZY sends you an email alert when your available licenses for a SKU are running low — at 50, 20, 10, 5, 2 and 1 remaining. ## License Activation When a license is activated by the Register API, the "Registered" column will change from "false" to "true" and the "Licensee" name will be displayed, along with the email. The "Date/Time" column will be updated with the time of activation. A license can be activated in two ways: - **Online:** The registration request is sent and KEYZY sets the "Registered" column to "true" - **Offline:** KEYZY needs to receive the license key and the product number to confirm the activation ## Editing a License To edit a license click on the license status, the licensee, or the email address. This will open a new window where you can edit: - The license status - The licensee name - The email address of the licensee The search bar allows you to search licenses by SKU name, serial number, status, dealer name, licensee, and email. --- ## App Keys Source: https://www.keyzy.io/docs/dashboard/app-keys/ App keys are used to authorize third-party applications to interact with KEYZY. ## Adding a New App Key 1. To go to the App Keys page, click the **App Keys** icon in the menu bar 2. To create a new App Key, click the **"Add new App Key"** button. To edit an existing App Key, click on its ID. 3. This will open a pop-up box where you can modify: - The write permission setting for the respective app key - Whether the app key is active or not ![App Keys Page](https://www.keyzy.io/dashboard-appkeys.webp) ## Applications with Write Access Typical examples of applications with write access are **web apps**. They request new licenses and need write authorization. Besides confirming if the serial number is correct, they can modify information, for example, the time of purchase. ## Applications without Write Access Typical examples of applications without write access are **desktop apps**. They can only query the server to confirm that the serial number is correct. ## Best Practices We suggest you create a **read permission** App Key for each application and a **write permission** App Key for each e-commerce store you have. The search bar allows you to search app keys by any term in the app key columns, by API key, or by app ID. --- ## Dealers Source: https://www.keyzy.io/docs/dashboard/dealers/ In the dealers menu you can add the dealers that sell your products. ## Adding a New Dealer 1. To go to the dealers page, click **dealers** icon in the menu bar 2. To add a new dealer click the **"Add new Dealer"** button. To edit an existing dealer, click on its name. 3. This will open a new pop-up box where you can modify the dealer's name. Having a dealer means that your software will be sold offline through a third-party website. If you want to sell your software offline through your own web-app, you need to add yourself as a dealer. ![Dealers Page](https://www.keyzy.io/dashboard-dealers.webp) The search bar allows you to search dealers by any term in the dealer columns, or by dealer name. --- ## Create an Account Source: https://www.keyzy.io/docs/account/create-account/ In order to create a new account, first go to [app.keyzy.io](https://app.keyzy.io/). You will be taken to KEYZY's dashboard landing page. Click on **"Create an Account"**. Enter your name, email address and password. After completing the form you will have access to your KEYZY account. Create Account --- ## Edit Your Account Details Source: https://www.keyzy.io/docs/account/edit-account/ To access your account details click on the **Account** button in the menu bar. To edit your personal information, modify the respective fields and then click the **"Save Profile"** button. ![Edit Account](https://www.keyzy.io/dashboard-account-edit.webp) --- ## Set Your Payment Plan Source: https://www.keyzy.io/docs/account/payment-plan/ First you need to access your account details by clicking on the **Account** button in the menu bar. Then click on **"Change Plan"**. At the following page you can select one of the available payment plans. In case you want to cancel your payment, you can do so at any time. ![Payment Plan](https://www.keyzy.io/dashboard-account-plan.webp) --- ## Cancel Anytime Source: https://www.keyzy.io/docs/account/cancel/ You can cancel your subscription anytime. There are no long-term commitments or cancellation fees. Cancel Subscription --- ## Cannot Contact License Server Source: https://www.keyzy.io/docs/faq/cannot-contact-server/ When an end-user encounters a "Cannot contact license server" error, it typically means the application is unable to establish a secure connection with KEYZY's API to validate the license. This is often due to local network restrictions, security software, or system configurations. Please follow the steps below to troubleshoot the issue with your customer. ## Standard Troubleshooting Before diving into logs, please verify the following common causes: 1. **Internet Connectivity:** Ensure the device has an active and stable internet connection. 2. **Firewall & Antivirus Allowlisting:** Security software (Windows Defender, 3rd party Antivirus, or Firewalls) may mistakenly block the connection. Ensure that the software has permission to make outbound connections or that `api.keyzy.io` is whitelisted on **port 443**. 3. **Corporate Network Restrictions:** If the user is on a corporate or restricted network (e.g., office, university, or VPN), the network administrator may need to explicitly allow access to the `keyzy.io` domain. 4. **Hardware ID Consistency:** Confirm that the user is not running MAC address spoofing software. KEYZY relies on hardware identifiers, and spoofing tools can disrupt the validation process. ## Advanced Troubleshooting: Diagnosing Network Issues If the issue persists, you may need to investigate the specific network response to pinpoint the failure (e.g., DNS resolution failure, SSL handshake blocking, or firewall termination). Ask your customer to run the following diagnostic command: ### For macOS and Linux Users 1. Open the **Terminal** app 2. Copy and paste the following command and press **Enter**: ```bash curl -v https://api.keyzy.io/v2/status-check ``` 3. Copy the entire text output and send it to the support team. ### For Windows Users 1. Press the **Windows Key**, type **cmd**, and select **Command Prompt** (do not use PowerShell) 2. Copy and paste the following command and press **Enter**: ```bash curl -v https://api.keyzy.io/v2/status-check ``` 3. Take a screenshot of the result or copy the text and send it to the support team. ## How to Analyze the Output Once you receive the output from your customer, look for the following clues: - **`Trying 127.0.0.1...` or `Trying ::1...`** — The domain is being redirected to localhost instead of KEYZY's servers. This is almost always caused by an entry in the user's **hosts file**. Ask the user to check their hosts file (`/etc/hosts` on macOS/Linux or `C:\Windows\System32\drivers\etc\hosts` on Windows) and remove any lines referencing `keyzy.io`. - **`Could not resolve host`** — This indicates a DNS issue. The user may need to check their internet connection or try changing their DNS settings (e.g., to Google DNS `8.8.8.8`). - **`Connect to ... timed out`** — This usually indicates that a **Firewall** or **Proxy** is strictly blocking the outgoing connection. The user needs to whitelist `api.keyzy.io` or allow HTTPS traffic on port 443. - **`SSL certificate problem`** — The user might be behind a corporate proxy or antivirus software that performs SSL inspection (Man-in-the-Middle). - **`HTTP/1.1 200 OK`** — If you see this, the network connection to KEYZY is healthy. The issue likely lies within the application integration or local configuration rather than the network. --- ## How to Deactivate an Offline License Source: https://www.keyzy.io/docs/faq/deactivate-offline-license/ You can use the **Offline License Life** feature for that. You set the Offline License Life value in your [SKU settings](https://www.keyzy.io/docs/dashboard/skus/) and after that, offline licenses are generated for X days. After X days, the KEYZY Client library's offline validation returns an "invalid" value and your customer needs to reactivate the license for the next X days. If you use semi-online activation schema, your customer doesn't get hassled for that operation. --- ## Offline License Life Source: https://www.keyzy.io/docs/faq/offline-license-life/ The Offline License Life parameter can be found on the [SKUs](https://www.keyzy.io/docs/dashboard/skus/) page. This parameter is only valid for semi-online and offline activations and can be applied to **Perpetual licenses**. It limits the license's validity time. For example, if you set 90 days to the Offline License Life parameter for an SKU, the license file will be valid for the next 90 days after the file is downloaded. It has to be downloaded at least every 90 days to use the license. If you have a refund policy or something like you need to cut the license validity, you might want to use this setting. --- ## C++ Library: Windows Crash or Hang During Activation Source: https://www.keyzy.io/docs/faq/cpp-windows-crash-on-activation/ If your Windows application crashes or hangs during a license call — most often in `activateSemiOnline()` — while offline checks like `validateOffline()` keep working, the cause is usually the **Visual C++ runtime**. Which fix applies depends on which library variant you linked. ## MT vs MD: which variant did you link? The C++ Client Library ships in two Windows runtime variants: - **MT (static runtime):** the C++ runtime is linked into your binary. **No Visual C++ Redistributable is needed** on the end user's machine. If you use MT, the issue below does not apply. - **MD (dynamic runtime):** your application depends on the Visual C++ Redistributable being installed on the end user's machine. **This is the variant where the crash occurs** when that redistributable is missing or outdated. If you are unsure, this crash strongly suggests you are shipping the **MD** variant. ## Why the MD build crashes The library is built with a recent MSVC toolset (v142 / v143). Some activation paths use the C++ threading runtime (`std::thread` / `std::mutex`, provided by `CONCRT140.dll` / `VCRUNTIME140_1.dll`), which needs a current Visual C++ Redistributable. An older one can be **present but too old**: offline-only calls like `validateOffline()` do not use the threading runtime and still run, so the problem only appears a step later, during activation. Seeing `MSVCP140.dll` or `VCRUNTIME140.dll` loaded in the process is not enough — the version matters, and `VCRUNTIME140_1.dll` in particular ships only with newer redistributables. ## The fix You have two options: 1. **Update the redistributable.** Ask the affected end user to install the latest Microsoft Visual C++ Redistributable (x64): https://aka.ms/vs/17/release/vc_redist.x64.exe — use the x86 build for a 32-bit application. To prevent this for every end user, bundle (or require) it in your own installer. 2. **Or link the MT (static runtime) variant.** This removes the Visual C++ Redistributable dependency entirely, so end users never need it installed.