1. Prepare the product and license
For a native C11 application, use the C SDK to activate a customer license and check feature access before invoking a business callback. Start with a device-bound license and an unmetered export; add usage counters after the basic flow works.
Device quota counts current activations and is returned on release. Ordinary licenses remain counted while offline; floating licenses also return quota when their leases expire.
- Copy the Product ID from Console > Products. Open that product’s Signing public keys and paste every key ID/public key pair into the initialization code, replacing YOUR_PRODUCT_ID, YOUR_KEY_ID and YOUR_PUBLIC_KEY. Quick integration can generate these public code constants. No product configuration file is required; the SDK defaults to https://www.licentivo.com.
- In Quick integration, create or select a product. Enable a feature named export in its policy and prepare a test license.
2. Install the SDK
Install CMake 3.18 or later. On Windows x64, use Visual Studio 2022 C++ Build Tools and the matching MSVC SDK package, with -G "Visual Studio 17 2022" -A x64. On Linux x64, use C11/C++17 compilers. Replace SDK_PREFIX with the CMake prefix printed by the installer. Save the example as app.c and the CMakeLists.txt below in the same directory.
Install a shared libcurl development package matching the compiler and architecture. For Windows MSVC x64, replace CURL_DIR with the directory containing CURLConfig.cmake, add curl's bin directory to PATH for local runs, and distribute the required DLLs with your application; on Linux, install your distribution's shared libcurl development package.
& ([scriptblock]::Create((Invoke-WebRequest 'https://www.licentivo.com/assets/sdk/releases/v0.11.6/install.ps1').Content)) -Language c -Toolchain msvccurl --fail --silent --show-error --location --proto '=https' --proto-redir '=https' 'https://www.licentivo.com/assets/sdk/releases/v0.11.6/install.sh' | bash -s -- ccmake_minimum_required(VERSION 3.18)
project(licensed_app LANGUAGES C)
find_package(Licentivo 0.11.6 REQUIRED)
add_executable(licensed_app app.c)
target_link_libraries(licensed_app PRIVATE Licentivo::C)
set_target_properties(licensed_app PROPERTIES C_STANDARD 11 C_STANDARD_REQUIRED ON)cmake -S . -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_PREFIX_PATH="SDK_PREFIX" -DCURL_DIR="CURL_DIR"
if ($LASTEXITCODE -ne 0) { throw 'CMake configure failed. Check the SDK prefix and matching libcurl development package.' }
cmake --build build --config Release --target licensed_app
if ($LASTEXITCODE -ne 0) { throw 'Build failed.' }set -e
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="SDK_PREFIX"
cmake --build build --target licensed_app3. Protect a real export
Move SDK startup into your application’s startup or activation handler. Read the customer key from your activation form, pass your own product ID and trusted keys, and keep the client alive until shutdown. Put ln_run_feature at the actual business entry point; replace the report writer with your own operation.
#include "licentivo.h"
#include <stdio.h>
#include <stdlib.h>
/* BEGIN LICENTIVO PRODUCT */
/* Copy Product ID and all key ID/public key pairs from Console > Products > Signing public keys. */
static const char *PRODUCT_ID = "YOUR_PRODUCT_ID";
static const char *TRUSTED_KEYS_JSON = "{\"YOUR_KEY_ID\":\"YOUR_PUBLIC_KEY\"}";
/* END LICENTIVO PRODUCT */
static const char *setting(const char *name, const char *fallback) {
const char *value = getenv(name);
return value && value[0] ? value : fallback;
}
static int export_report(void *context) {
const char *path = (const char *)context;
/* Replace this write with your existing, non-metered export operation. */
FILE *file = fopen(path, "w");
if (!file) { perror("Export write failed"); return 0; }
int wrote = fputs("A report generated by the licensed application.\n", file) >= 0;
int closed = fclose(file) == 0;
return wrote && closed;
}
int main(void) {
/* Keep the handle to report startup errors. A GUI supplies the activation input. */
ln_client *client = ln_init_product(PRODUCT_ID, TRUSTED_KEYS_JSON, setting("LICENTIVO_LICENSE_KEY", ""));
if (!client) {
fputs("Startup failed: check the product ID and public keys and supply a license key for first activation.\n", stderr);
return 2;
}
if (!ln_start(client)) {
fprintf(stderr, "Startup failed: %s\n", ln_last_error(client));
ln_destroy(client);
return 2;
}
const char *feature = setting("LICENTIVO_FEATURE", "export");
const char *path = setting("LICENTIVO_OUTPUT", "licensed-report.txt");
int ok = setting("LICENTIVO_METERED", "")[0] == '1'
? ln_run_metered_feature(client, feature, 1, setting("LICENTIVO_OPERATION_ID", ""), export_report, (void *)path)
: ln_run_feature(client, feature, export_report, (void *)path);
if (!ok) {
char *status = ln_feature_status(client, feature);
fprintf(stderr, "Export denied or failed: %s; %s\n", status ? status : "status unavailable", ln_last_error(client));
ln_free_string(status);
}
if (ok) printf("License OK: %s is available\nExport completed: %s\n", feature, path);
ln_destroy(client); /* Real app: destroy on shutdown; no Deactivate on normal exit. */
return ok ? 0 : 2;
}
4. Keep the client alive until shutdown
This command-line example performs one operation and exits. In a desktop application, open one client at startup, invoke the feature callback from the export action, and close the client only when the application exits.
After activation, later starts can leave LICENTIVO_LICENSE_KEY empty and restore the private credential under the same user and cache location. Keep that credential in the user application-data directory. Closing stops heartbeats and returns floating seats; normal exit should not deactivate a node-locked device.
Offline access is available only when the policy permits it and the signed grant remains valid. An expired or denied feature must remain blocked. Metered operations require a network connection.
Keep the ln_client handle until shutdown. ln_start performs startup authorization; only ln_run_feature or the metered variant may invoke protected work. The callback returns 1 on business success and 0 on failure. Release allocated status strings with ln_free_string, then call ln_destroy on shutdown.
5. Run and verify the result
- Confirm that a valid license with export access creates licensed-report.txt.
- Clear LICENTIVO_LICENSE_KEY and run again using the same user account: the saved credential should restore.
- Set LICENTIVO_FEATURE to a feature absent from the license and LICENTIVO_OUTPUT to a fresh filename. The program must report a denial without creating that file.
- Test an offline restart only with a permitted, unexpired signed grant. Do not bypass a failed feature check after a background refresh error.
$env:LICENTIVO_LICENSE_KEY = 'YOUR_TEST_LICENSE_KEY'
./build/Release/licensed_app.exe
Remove-Item Env:LICENTIVO_LICENSE_KEY
./build/Release/licensed_app.exeLICENTIVO_LICENSE_KEY=YOUR_TEST_LICENSE_KEY ./build/licensed_app
unset LICENTIVO_LICENSE_KEY
./build/licensed_appCommon integration problems
Check the product ID, every key ID/public key pair and the customer’s license input. Public verification keys belong to a product; customer licenses and saved device credentials are separate. Do not distribute development test keys or vendor management API keys.
Feature denied, device limit reached or license expired: inspect the license and policy in the console, then show the SDK error to the customer. A failed authorization must not call the export function.
RunFeature checks feature access; the metered variant reserves and settles configured usage. Use a stable operation ID per real business job and inspect its durable result before recovering an interrupted job.
CMake cannot find Licentivo: replace SDK_PREFIX in the configure command with the CMake prefix printed by the installer. Compiler, architecture and libcurl must match the installed native package.