Skip to content
Developer docsQuick start

Add licensing to your software

Run the demo first, then accept customers' license keys in your application. The SDK handles device identity, signatures, cache and heartbeats. Check permissions before each paid feature.

  1. Download integration bundleGenerate product settings in the console
  2. Run the exampleCheck connectivity and test licensing
  3. Add to your applicationPass the customer's own license key

1. Prepare your bundle in the console

Open Quick start, enter a software name, choose device-bound or floating licensing, and select Create product, then continue. The system prepares the product, policy, test license, public key and version 1.0.0. Choose a language, download the configured bundle and extract it.

The bundle contains two configurations:sdk-demo.json contains a test license key for your own tests;product.json contains only product settings and the public key, and can ship with your software.

2. Run the complete demo

Open a terminal at the extracted bundle's root, choose your language and system, then run the command below. For required compilers or runtimes, see Client SDK.

Run in the extracted directory

Success looks like this:The demo activates, validates, sends a heartbeat and deactivates, then exits normally with code 0. The last line of the Go demo is Go: deactivated; see the output for other languages. On failure, start with Error codes and troubleshooting.

3. Add it to the customer's application

Add the SDK and product.json to your application. Accept the customer's key in your activation window and call the language's OpenWithLicense, the SDK saves a machine credential after activation. Pass an empty string on later starts.

Before paid operations such as export, call CheckFeature("export"), and proceed only if the check passes. Keep the client alive with the application and close it on exit.See minimal code in seven languages →

Keep test configuration separate from customer licenses.

Ship only the required SDK and product.json. Each customer has their own key. Exclude sdk-demo.json, cached leases, device credentials and management API keys. An empty cache_path selects a private per-user directory.

Know these three identifiers

NameUsed byPurpose
License key lv_lic_…The software buyerActivate inside the application. The temporary device-transfer code lv_tmp_… also goes in the same field.
Product IDSDK / Software developerIdentifies the product being validated; safe to distribute with the application.
Management API keyThe vendor's serverAutomates license issuance, renewal and management. Client activation does not need it.

Set the heartbeat interval and offline duration separately in License policies. License validity starts at first activation. Add feature quotas, floating seats and offline file activation after the basic integration works.

Without signing up, you can open Try the demoto inspect requests and responses. To automate license issuance, continue with Management API key.

Client SDK

Embed the SDK in your customer's application. It contacts the licensing server, verifies signatures and device identity, and manages the offline cache. Check feature permissions at your business entry points.

Before you run

In the console, Quick startdownload the configured bundle. The demo uses the private sdk-demo.json; in your actual application, use product.json, with the customer's key passed at startup. Download SDK below provides generic source, without your product settings.

What does each configuration field mean?
product.json · Shared product settings
{
  "base_url": "https://www.licentivo.com",
  "product_id": "PRODUCT_UUID",
  "license_key": "",
  "device_name": "Customer app",
  "app_version": "1.0.0",
  "trusted_keys": {
    "SIGNING_KEY_UUID": "BASE64URL_PUBLIC_KEY"
  },
  "timeout_seconds": 10,
  "allow_http": false
}
base_url
Licensing server URL: domain and port only, without /api/v1. For local testing, use https://127.0.0.1:8080.
product_id
This application's product ID. It must match the license's product.
license_key
Leave this empty in product.json. Pass the customer's key to OpenWithLicense: lv_lic_… or a device-transfer code: lv_tmp_…; this does not modify the shared configuration.
app_version
Current version in major.minor.patch format, for example 1.0.0. Required when version ranges or maintenance are enabled. Validate online again after changing versions.
device_name
Device name displayed in the console. It helps you recognize devices, but does not determine device identity.
trusted_keys
Product signing key ID and public key. Distribute them with your app or an authenticated update. Never trust a public key supplied by an unknown response.
cache_path
Omit or leave empty to use a private per-user directory automatically, or choose your application's own private file location.
timeout_seconds
Request timeout in seconds: default 10, range 1–120. Temporary network failures allow at most two attempts.
proxy_url
Optional proxy URL. Java uses an HTTP proxy; Node.js requires undici when a proxy is configured. Certificate verification stays enabled.
allow_http
In production, keep this set to false, using HTTPS. For local tests, set it to true, but only for localhost or loopback addresses.

You do not need to enter device_id: the SDK reads local device identity. The public keys in product.json can be distributed; keep customer keys and sdk-demo.json private.

Choose your language

The minimal example uses the ZIP's import paths. For terminal testing, LICENTIVO_LICENSE_KEY supplies the customer's key. In your app, use activation input once, then an empty string to restore. Use the full demo to check configuration and connectivity.

Activate and start heartbeats, then check export permission before exporting. Keep client alive for the application's lifetime.

Go · Client licensing
正在加载代码…

Pass a license key to the minimal example

Set the environment variable in your terminal, then run the example above. A license key is different from a management API key.

Environment variable for this terminal

On success, the output is License OK: export is available. In your application, collect the key through the activation form. Customers need no environment variable; the SDK saves the machine credential. Do not log their key.

Run the bundle's complete demo

Extract the ZIP without changing its directory structure. Place sdk-demo.json in the extracted root directory. Choose the operating system, open a terminal there, and run:

Terminal command

The demo releases the device at the end.

The command-line demo tests the whole workflow. Device-bound licenses normally keep their registration until a device transfer. Floating licenses return the seat on exit; after a crash, the server reclaims it when the lease expires.

Run an application example

Examples include activation input, status, file export and device release. Java, Python and C# have windows; other languages use terminal menus. Enter a key once, then leave it empty to restore.

Application example · selected language and system

A successful export creates licensed-report.txt. Configure an export quota in the policy before using metered export.

The Python example saves a job journal. Other examples retain pending jobs only until the process exits. Production apps must persist jobs and results to resume confirmation after a crash.

How to display authorization status

Status and FeatureStatus read locally without requests or waiting for background verification. Use status notifications to update your UI.

StatusMeaning
activeThe last online verification succeeded; local authorization is valid.
offline_validThe local signature is valid; online confirmation has not succeeded since startup.
verification_requiredNo usable signature. Activate or refresh online.
expired / revoked / releasedThe server explicitly denied authorization. Stop protected operations.
quota_exhaustedThis metered request exceeded its allowance; other entitled features remain available.

allowed describes local authorization validity; metered features still request units. lease_valid_until is the signed cache deadline, not final license expiry. code, request_id and retryable identify the error, log reference and whether retry is possible.

See sdk/README.md in the ZIP for method names, callbacks and local installation. Packages can be built locally; GitHub and public registries are not published yet.

Where does this belong in your application?

Application stageWhat to do
On startup or after key entryCall OpenWithLicense (constructor and Start in C++). The SDK activates and starts heartbeats according to the policy.
Before paid featuresCall CheckFeature, for example for export; block the operation if it returns false
While the application runsKeep client alive; the SDK sends heartbeats at the policy interval.
On application exitClose / Dispose / Destroy stops heartbeats, returns floating seats and preserves device-bound registrations.
When the user unbindsCall Deactivate, then close client.

Method names in the table identify operations; use the exact names in your language's example. For heartbeats, offline caches and online refresh, see Heartbeats and offline access.

Management API key

Use a management API Key to issue licenses automatically from your order system or read licensing data from a server. It represents your vendor workspace.

Which key does the client need?

CredentialWho receives itWhat it is for
lv_api_…
Management API key
Your own serverCreate products, policies and licenses; view devices, usage and audit logs
lv_lic_…
License key
Customer applicationActivate, validate, send heartbeats and release the device
Product public keyShip with the clientVerify the server's license signature

For licensing checks in customer software, a license key is enough. A management API Key can control the whole workspace; never embed it in customer software or public pages.

Create a key

  1. Sign in as the workspace Owner and open API Key and click Create API Key.
  2. Name it after its purpose, such as “Order system”. Choose Read only for queries or Read/write to create or change licenses. Validity can be 1–365 days.
  3. Copy the full Key immediately after saving; it is shown only once. Store it in private server configuration or an environment variable.

Send your first management request

This example reads the product list. Set LICENTIVO_URL to your license server URL and set LICENTIVO_API_KEY to the complete key you just created, then run:

curl
curl "$LICENTIVO_URL/api/v1/products?limit=25" \
  -H "Authorization: Bearer $LICENTIVO_API_KEY"

This syntax is for Bash/macOS/Linux. In Windows PowerShell, use curl.exe; the environment variable is $env:LICENTIVO_URL and $env:LICENTIVO_API_KEY. Full request examples in all seven languages are also in Server management API Key option on the SDK page.

Success returns HTTP 200 with data.items. Bearer Key management requests need neither login cookies nor CSRF tokens.

Permissions and invalidation

Read-only Keys can view resources; read/write Keys can also create and change products, policies and licenses. Management Keys cannot manage accounts, teams, system settings or payments; those require an authorized account login.

Revoke a leaked or unused Key in the console. To replace it, click Rotate; the old Key stops working immediately. Then update your server configuration.

Plan API quotas count activation, validation, heartbeat and release requests. These management requests do not count toward that quota.

Product and license API

Issue licenses from your own server after an order: create the product and policy, then a license for each customer. Usually the product and policy are configured once.

First create a write-enabled Management API key. The examples below use Authorization: Bearer 你的管理Key; keep this key on the vendor's server.

What should I save after creation?

Use the product's data.id as product_id and the policy's data.id as policy_id. After issuance, save the license's data.id and data.key. The full license key is returned only once; key_prefix in lists cannot activate software.

For a timed license before activation,expires_at and first_activated_at are null. The term starts at first successful activation; transfer does not grant a fresh term.

Further management

Method and path (without /api/v1)Purpose and request body
GET /productsList products. In the response, data.items is the record array and data.total is the total count.
GET /licenses/{id}Read license details, first activation and expiration.
POST /licenses/{id}/renewRenew, e.g. {"days":30}. Keeps the original license.
POST /licenses/{id}/revokeRevoke; request body is {}.
GET /products/{id}/public-keysRead the product's public keys without authentication. Pin trusted keys when distributing the SDK.
GET /activationsView device bindings and runtime sessions.

List pagination uses limit=25&offset=0, limit is at most 100. Other parameters and schemas are in OpenAPI file; see the relevant topic on the left for each license model.

How do I call with a browser login session?

Writes using browser cookies require X-CSRF-Token. First GET /api/v1/auth/csrf, then put data.csrf_token in that header. Bearer Key requests do not require CSRF.

License validation API

The HTTP requests below follow a real integration flow. The SDK handles requests, signature checks and cache storage automatically; use this reference to inspect responses or build your own client.

First activationRuntime heartbeatCheck access before business operationsDeactivate before device transfer

These five endpoints authenticate with a license key and device identity, without login cookies, CSRF or vendor management Keys. On exit, floating licenses release the session; device-bound licenses keep their binding.

How do I check access after activation, validation or a heartbeat?

  1. Check for HTTP 200 and read data.activation_id. Include this ID in later validation, heartbeat, metering and deactivation requests.
  2. Verify with the pre-trusted product public key data.lease signature, then verify the product, device, validity and features. Decoding payload into JSON alone does not prove a license is valid.
  3. Use the SDK's CheckFeature Check whether a feature is allowed. To limit uses, also call Consume and perform the business action only after it succeeds.

The SDK stores signed caches and sends policy-based heartbeats. Do not erase a valid cache just because a request times out. For explicit revocation, release or expiration, use the SDK result to block protected features.

What do decoded payload fields mean?

The example below only explains the data. If implementing signature verification, use the received payload's original bytes; do not reorder or serialize the JSON before verifying.

Payload example

Retries, heartbeats and billing

Required for activation, deactivation and feature metering Idempotency-Key, up to 80 characters without whitespace. Generate a new value for each operation; keep the same value and body when retrying it. Optional for validation and heartbeats; the SDK handles its own request IDs.

Each successful activation, validation, heartbeat or unbinding uses one platform API call. Failures and idempotent replays are not counted again; local CheckFeature makes no request. Consume only deducts software feature uses, not this platform API quota. quantity is the number of feature uses consumed.

Heartbeat interval, offline duration and permanent offline follow License policies settings.payload.expires_at is the current signed cache's expiration, not the license's final expiration. Check license details for the latter.

Heartbeats and offline access

Both settings belong to Licensing policies but answer different questions: how often to contact the server online, and how long use can continue without reaching it.

Heartbeat interval: how often to validate

Set Heartbeat interval (seconds) to 600, the SDK sends a heartbeat roughly every 10 minutes while running. Each success retrieves the latest rules and refreshes the local license cache.

Enter 600–86400 seconds. Enter 0 disables scheduled heartbeats. Your application can still verify or refresh manually. Scheduling adds 0–10% random delay; the interval never falls below 600 seconds.

For a device-bound license with a valid cache, startup restores access and refreshes online in the background, even with the timer disabled. Online-only and floating licenses wait for server confirmation.

Offline allowance: how long to run without the server

Offline mode has three choices. It does not change the heartbeat interval.

Allow for a specified duration
For a 24-hour allowance, the signed cache lasts at most 24 hours from the last successful online check. The app can work through a disconnection or temporary server outage within that time. Afterward, online validation must succeed.
Offline fallback not allowed
Startup must reach the server successfully; disk caches cannot bypass a failed request. A short-lived signature obtained while running lasts at most max(10, 心跳间隔) seconds; the app must keep validating and checking feature permissions.
Allow permanent offline access
An existing local signature can be used long term, including during network failures. A 30-day license still expires after 30 days; permanent offline use does not make a timed license perpetual.

The API uses offline_mode represents these three choices, respectively limited, none, permanent. With a fixed offline allowance,offline_seconds is 1–31536000 seconds; use 0 for the other two modes.

How do these combinations behave?

Heartbeat / offline settingsActual behavior
10 minutes / 24 hoursValidate every 10 minutes online. Offline, continue for at most 24 hours after the last successful check
10 minutes / permanent offlineStill tries a heartbeat every 10 minutes, updates rules on success and uses a valid signature when unreachable.
0 / permanent offlineWith a valid cache, startup needs no scheduled requests. Explicit validation or refresh still contacts the server
0 / 24 hoursNo scheduled heartbeats, but cache still expires. The app must schedule validation; disabling heartbeats does not extend offline allowance.

Keep the offline allowance longer than the heartbeat interval. With hourly heartbeats but only 1 minute offline, the signature expires before the next heartbeat; the app must validate separately.

Do policy changes update existing licenses?

Yes. Changed heartbeat or offline settings apply to both existing and new linked licenses on the next successful activation, validation or heartbeat. The SDK replaces the signed cache. A retry with the same Idempotency-Key still returns the original request's result.

An offline device keeps using its existing signed rules. Reconnecting alone does not update its cache; a request must succeed. Your app can refresh actively when connectivity returns.

This updates runtime rules.

Validity days, device limits and features are stored per license. Editing a policy does not automatically rewrite them. Change individual license rights on the Licenses page.

Explicit online refresh

These methods always try the server, even with permanent offline use and heartbeats disabled. Success updates the signature. Network failure reports a refresh error but keeps an otherwise valid cache. Explicit revocation or release clears it.

LanguageHow to call
Goclient.RefreshOnline(ctx)
Javaclient.refreshOnline()
Cln_refresh_online(client)
C++client.RefreshOnline()
C#await client.RefreshOnline()
Pythonclient.refresh_online()
JavaScriptawait client.refreshOnline()

A successful refresh counts as one activation API request. If a policy change enables previously disabled heartbeats, call your language's StartHeartbeat to start scheduling. Offline devices cannot receive revocation or release updates.

Device binding

With a single-device license, copying software and its cache to another ordinary computer does not transfer the original computer's authorization.

How does the SDK identify the computer?

At each start, the SDK reads the OS machine identity and hashes it with the product ID. The server's signature includes this hash, which is also checked locally.

Windows reads MachineGuid, Linux reads machine-id and macOS reads IOPlatformUUID. Raw machine identity is not uploaded, only its calculated hash. The legacy config field device_id does not override the actual local identity.

What happens if files from machine A are copied to B?

  1. A activates and receives a signature bound to A's device hash.
  2. B reads its own identity, gets a different hash and rejects A's cache.
  3. B must activate online. With a one-device limit and A still bound, the server rejects B.

How can a customer change computers?

Have the customer unbind the old computer, then activate the new one. If the old one is broken, release its binding in Device activations in the console. Moving computers does not reset license expiration.

Reinstalling the operating system may change its identity and require a new-device activation. Full OS cloning, spoofed identities or modified clients are stronger attacks; this device hash alone cannot reliably stop them.

With long offline use, A's existing signature cannot immediately learn it was released. A successful server request is needed to update that state. Longer offline periods delay remote enforcement.

Cross-language device hash
All seven SDKs use the same algorithm
SHA256(UTF8(
  "LicenovaDevice/v2\n"
  + lower(product_id) + "\n"
  + lower(trim(OS_machine_identity))
))

Quotas and billing

Device quotas count devices used; API quotas count successful server requests. They are separate measures; device count cannot determine API usage.

Which operations count toward API usage?

ActionCounted?
Successful activation, validation, heartbeat or releaseEach success counts once; separate heartbeats on the same day each count.
Failed requests, e.g. invalid key or insufficient allowanceNot counted
Retry with the same Idempotency-Key and return the original resultNot counted again
Local CheckFeature or signed-cache checkNot counted; no server request
Query or issue licenses with a management API KeyNot included in this runtime API quota

Do repeated requests count a device more than once?

No. Within one billing period, the same device for the same product counts once as device usage, but every successful heartbeat counts as API usage. Releasing it does not erase prior usage.

For example, 100 devices running 8 hours a day, 22 days a month, with 10-minute heartbeats produce this many heartbeats alone: 105,600 calls. Add 100 activations and one extra validation per device each day, giving 107,900 calls.

Extra validations are assumed for this example; actual usage depends on your app. In Online usage estimator adjust devices, run time and request interval.

How is plan overage charged?

For a plan with 100,000 API calls and 0.0001 USD per extra call: 120,000 successful calls mean 20,000 extra, with an API overage fee of 2 USD.

Plans allowing overage deduct balance at administrator prices. The cumulative amount is rounded to cents and only its increase is charged, so tiny per-call prices do not cause repeated rounding charges.

Device overage is separate: excess devices × device unit price. A hard limit rejects further requests for that quota. Insufficient balance also rejects the next chargeable request. Rejected requests do not add usage.

Unlimited API quotas have no API overage fee. A quota of zero includes no free calls, so overage rules apply from the first successful request. For included quotas, prices and limits, see Current plan, these figures are examples only.

When do package duration and quota start?

Buy 1, 3, 6 or 12 months. Pay the total once; the package starts after successful payment.

Device and API quotas reset monthly from activation. A January 31 start resets on February's last day, then March 31. Unused quota does not carry over.

Without a purchase, administrator defaults apply by UTC calendar month. Default device fees use monthly invoices; default API overage is deducted from balance immediately. A purchased plan uses its own period's quotas, without adding default quotas.

If quota or balance shortages reject a runtime request, existing offline signatures remain valid under their original rules. Vendors can release devices in the console without consuming the customer's runtime API quota.

Floating seats

Floating licensing limits simultaneously running programs. It suits people sharing software at different times, without buying a separate license for every computer.

Example

For 100 computers with 10 floating seats, the first 10 programs can start; the 11th gets “No seats available”. Once a program exits and closes its SDK normally, another can take that seat. Two programs on one computer consume two seats.

Set in the policy

Choose floating seats and set the limit to 10. Heartbeats must be at least 600 seconds apart; seat leases must be longer, for example 1200 seconds. Heartbeats renew the lease; after a crash or disconnection, expiry frees the seat.

Floating licenses allow brief disconnection within their lease. Offline time is also bounded by that lease; permanent offline use and file-based fully offline first activation are not supported.

What else should application code handle?

Use Open/Start and the normal close method. The SDK creates a separate session ID for each client. Do not create a client for every export; keep one for the application's lifetime.

An old floating cache does not restore a seat automatically on the next process start. If its lease expired, activate again and acquire a seat before resuming work.

Offline activation

For a fully offline computer, use a request file and signed response for first activation. Carry the request by USB drive to an online computer.

Steps

  1. On the target computer, load SDK configuration, call OfflineRequest("activate") and save the request file. Creating it does not contact the server.
  2. On an online computer, open Offline file activation in the console, upload the request and download the response. End customers can also use their customer portal.
  3. Bring the response back and call ImportOffline with the original request and response. The SDK verifies signature, request ID, version and machine identity, then saves the cache.
  4. Use CheckFeature to check authorization. Offline computers do not need online heartbeats; the licensing policy determines the offline duration.

File activation supports only device-bound policies that allow offline use. Requests last 30 days. Timed licenses start when the server approves the request, since it cannot know when the response is imported.

How do I deactivate offline?

On the original computer, generate OfflineRequest("deactivate"). The SDK deletes its cache first; then submit the request to the vendor or customer portal. Deletion cannot prove no older copies exist. For prompt revocation, use policies requiring periodic online checks.

Names in each language

LanguageGenerate requestImport response
GoOfflineRequest("activate") → []byteImportOffline(requestBytes, responseBytes)
JavaofflineRequest("activate") → JSON textimportOffline(requestText, responseText)
JavaScriptofflineRequest("activate") → objectimportOffline(requestObject, responseObject)
Cln_offline_request(client, "activate")ln_import_offline(client, requestText, responseText)
C++ / C#OfflineRequest("activate") → JSON textImportOffline (text in C++, bytes in C#)
Pythonoffline_request("activate") → dictimport_offline(requestDict, responseDict)

In C, free returned strings with ln_free_string. Pass the response file's actual contents, not the web API's outer data wrapper.

Feature usage limits

“Allow export” and “Allow 500 exports per month” are different rules. CheckFeature checks permission; Consume records actual use.

Allow 500 exports per month

Add export to the policy's features, then a quota: feature export, limit 500, period Monthly. By default, further use is rejected when exhausted. To allow overage, set its maximum; the system records excess usage for your order system.

Daily and monthly quotas reset at midnight UTC; lifetime quotas do not reset. Changing a limit does not erase consumed usage.

Confirm usage after a successful export

  1. Create and save a job ID for this export.
  2. Reserve one unit and export only after pending. committed means the work already finished; do not execute again.
  3. After exporting successfully and saving the result, call Commit to confirm the use.
  4. If the export fails before completion, call Cancel to release the hold without consuming units.

Holds last 15 minutes by default, shortened at a UTC reset. Direct API callers can set reservation_seconds to 30–3600 seconds.

LanguageReserveCommit / Cancel
GoReserve(ctx, "export", 1, jobID)Commit / Cancel(ctx, hold.ID, jobID)
Java / Node.jsreserve("export", 1, jobID)commit / cancel(id, jobID)
Cln_reserve(client, "export", 1, jobID)ln_commit / ln_cancel(client, id, jobID)
C++ / C#Reserve("export", 1, jobID)Commit / Cancel(id, jobID)
Pythonreserve("export", 1, jobID)commit / cancel(id, jobID)

How to read the response fields

FieldMeaning
reservation_id / operation_idReservation ID and original job ID; keep the same values for retries.
status / expires_atHold status and deadline: pending awaits completion, committed is charged, canceled is released, expired has timed out.
consumption.used / reservedConfirmed uses this period / units held by all active reservations.
consumption.limit / remainingBasic allowance / available basic units. remaining = max(0, limit - used - reserved), excluding permitted overage.
consumption.quantity / overageUnits for this job / confirmed units above the basic allowance; no customer payment is collected.
consumption.period / reset_atUTC usage period / next reset; lifetime allowances have reset_at = null.

For request bodies, responses and field types, see Reserve, Commit and Cancel in the runtime API reference.

After a commit timeout, retry only the commit.

After success, do not cancel or export again. Retain the IDs and result and retry Commit. If the hold expired, keep the job for reconciliation. Remote usage and local business work cannot share one atomic transaction.

Consume still records usage immediately. Use reservations to avoid charging failed work. All functional usage endpoints require a connection and are excluded from the platform's four billable API operations.

Versions and maintenance

A perpetual purchase allows continued use, but not necessarily free upgrades forever. The maintenance period determines eligibility based on each version's release date.

Own the current version, updates included for a year

Set the policy to Perpetual with 365 maintenance days. Maintenance begins at first activation. Publish versions such as 1.0.0 and 1.1.0 in Software versions with their actual release dates.

Versions released during maintenance remain usable. New versions released afterward are rejected, while old ones still work. After a customer renews maintenance, extend it in the license's Rights and customer settings.

How does the app report its version?

Set app_version in sdk-demo.json, for example 1.1.0. With maintenance enabled, publish that version in the console first. Only three-part numeric versions such as 1.2.3 are supported. Published release dates cannot be changed, protecting already sold rights.

To allow only 1.x, set minimum 1.0.0 and maximum 1.999.999 without maintenance. After an update, go online to obtain a signature for the new version; an old version's cache cannot authorize it.

Provide downloads

Version records can include an HTTPS download URL and SHA-256 checksum. The portal shows only eligible versions. These records provide links; they do not upload installers or automatically install updates for customers.

Customer portal

Customers can check licenses, view devices and unbind them without entering the vendor console.

Vendor links the customer email first

Enter customer email on issuance or under Entitlements and customer. Send the Customer portal link to the customer. Entering that email sends a one-time login link, valid for 15 minutes. The login session lasts 24 hours.

Customers see only licenses linked to that email, not your product management, bills or other customers' data. Configure the email service in administrator settings first.

What if the customer lost their key when changing computers?

  1. The customer enters the license's linked email and opens the login link sent there. This link logs them in; it does not unbind a device.
  2. Under My devices / sessions, choose the old computer, Deactivate and transfer, then confirm.
  3. The page shows a temporary activation code, valid for at most 15 minutes and one successful activation. Customers can copy it or choose to email it to themselves.
  4. On the new computer, open your app and enter the temporary code on its activation screen. The SDK identifies the computer, binds the original license and saves device credentials. Restarts and heartbeats use those credentials; code expiration does not affect the activated computer.

This changes only the device binding. License ID, original expiration, features, customer and consumed usage remain; no new license is issued. The new device must meet the original policy and have an available device slot.

What does the software vendor need to change?

Upgrade to the current SDK. The field that accepts license keys can also accept lv_tmp_ temporary transfer codes; put one in the config's license_key is sufficient; Start, validation and heartbeat work as usual. The SDK saves the device credential in a private cache directory;cache_path can be empty. Keep this file in the current user's application data directory; never distribute it with the installer.

After successful redemption, the app can clear license_key blank; keep the same product, public keys and cache_path, the SDK restores device credentials on restart. Customers need not save or re-enter the temporary code. Until redemption succeeds, keep their input so it can be retried after a disconnection.

If the code expires or this page is closed

Log into the portal again to see unused codes. After an unused code expires, choose View/get activation code beside its released device to reissue it without another transfer count. Used codes cannot be redeemed again or repeatedly issued from old records to bypass limits. For another transfer, unbind the currently active device.

If the new computer is fully offline

Enter the temporary code on the new computer and export an activation request with the SDK. Before the code expires, take it to an online computer and get a portal response, then import it on the new computer. The policy must allow offline device-bound activation. The original license term remains; protect the response containing this machine's authorization and credentials.

Deactivation limits and the old computer

Set self-service release limits in the policy, per license per UTC month. Zero disables new portal unbindings. Repeated clicks, viewing codes and reissuing expired unused codes do not add counts. This limit covers the portal and customer offline release requests, not manual vendor releases or software release calls using the original license key.

Remote unbinding blocks the old device's next online check. Existing offline caches remain until checking online or expiring. Permanent offline caches cannot be stopped immediately remotely; use periodic online policies when prompt revocation matters. Ordinary copies of configuration, credentials and caches on another computer are rejected because its machine identity differs.

The customer portal manages license use. Vendor orders and software sales payments remain in the vendor's own system.

Event notifications

When a license activates, renews or is revoked, Licentivo can notify your server to synchronize orders, customers and support systems.

Add notification endpoint

Open Licensing event notifications, add your server's HTTPS URL and select events. Saving shows the signing secret once; store it on the receiving server. Production does not allow local or private network destinations.

Verify the signature after receipt

Read X-Licentivo-Timestamp, X-Licentivo-Event and the raw request body. Join timestamp + '.' + event ID + '.' + body, calculate HMAC-SHA256 with the signing secret, prepend sha256= and compare with X-Licentivo-Signature in constant time. Reject timestamps more than 5 minutes from now.

Deduplicate by event ID. Verify the signature, place the event in your transaction or queue, and return 2xx after durable storage. For duplicates, return 2xx without repeating order actions.

What happens on failure?

Delivery is tried up to 8 times automatically with increasing delays. The console shows HTTP status, attempt time and errors, and permits manual redelivery. Events and license operations share a database transaction; delivery resumes after a restart.

Events cover creation, updates, renewal, revocation, activation, release, feature consumption, upcoming expiration, expiration and maintenance changes. Notifications include only the license prefix, never its full key.

Bulk operations and policy changes

Issue, renew or revoke licenses in a batch when customers need the same treatment. Preview the impact before changing existing license rights.

Bulk issue or import

On Licenses, choose Batch issue/import and select a product and policy. Enter each customer's name and email, or upload CSV with customer,customer_email headers. Maximum 100 rows per batch. Download issuance results and retain full license codes.

If any item fails, the entire batch remains unapplied. After a timeout, retry without changing the contents; the request ID returns the original result rather than issuing again.

Bulk renew or revoke

Select licenses on the left, then Batch renew or Batch revoke. The header checkbox selects the current page; selections survive pagination, up to 100 per batch. Changing filters, leaving Licenses or refreshing clears the selection.

Enter days to add when renewing. Unactivated licenses gain validity days; active ones extend their expiration; expired ones extend from now. Before revoking, expand the selection to check customers. Revocation is irreversible. Read-only members cannot perform these operations.

Apply a new policy to existing licenses

  1. Save the new rules under License policies.
  2. Select existing licenses for one product, choose Apply policy and select the new policy.
  3. Review changes to validity, devices/seats, features, usage and maintenance. If occupied seats exceed the new limit, or active devices remain while changing binding mode, the system requires resolving devices first.
  4. Apply after confirmation. The next online check receives a new signed authorization; existing fully offline caches cannot be changed remotely.

Previews last 10 minutes. If a license or policy changes afterward, preview again. Applying new validity days recalculates expiration from the original first activation, so check the previewed dates first.

Common questions

Start with the returned error code, then check its settings. The response's request_id helps find this operation in server logs. Do not put full keys in logs or screenshots.

What should I check if activation fails?

Check that the server URL is reachable, product ID is correct, the license code is complete and belongs to this product. Until deployment, customer computers cannot use your 127.0.0.1 address; it refers to the customer's own computer.

Error codeFirst step
LICENSE_INVALIDCheck product ID, full license key and license product
LICENSE_EXPIREDCheck license expiration; the vendor renews it when needed
LICENSE_REVOKED
DEVICE_RELEASED
License revoked or device released; SDK clears old cache
DEVICE_LIMIT_REACHEDLicense device slots full; release an old device or increase its limit
API_QUOTA_EXCEEDEDAPI hard quota exhausted; check the period and plan limits
API_BALANCE_INSUFFICIENTInsufficient API overage balance; check currency and environment
MONTHLY_QUOTA_EXCEEDEDPlatform device cap reached; separate from the license's device limit
IDEMPOTENCY_CONFLICTSame Key used for different bodies; new operation needs new Key, retries retain the original body
IDEMPOTENCY_EXPIREDOld response or device binding invalid; check state and use a new Key for a new operation

Why does it still work offline?

Offline use still checks the server signature, product, device, features and expiration locally. Only the server request is omitted. Expired caches or explicit online revocation/release responses block further use.

Why does signature or device verification fail?

A mismatched public key, another product's cache or a cache copied to a different computer can cause failure. Check trusted_keys uses the current product's key ID and public key, then check whether the operating system was replaced or reinstalled.

SDK reports clock rollback : check whether the clock moved backward. Correct it, then explicitly refresh online.

Complete error response

HTTP 403 · license revoked
{
  "error": {
    "code": "LICENSE_REVOKED",
    "message": "License was revoked"
  },
  "request_id": "99999999-9999-4999-8999-999999999999"
}
FieldMeaning and action
error.code · stringStable error identifier for program logic; do not rely on message wording.
error.message · stringHuman-readable failure reason for diagnosis or a customer-facing message.
request_id · UUIDServer-generated HTTP request ID for logs; not the license ID or Idempotency-Key.

For 400/415, fix fields or Content-Type; 401: check the management Key; 403: handle the specific licensing error; 409: check quota, session or idempotency conflicts; 429: wait as Retry-After specifies. Retry timeouts or 5xx with delays. For writes, reuse the original idempotency ID and body to avoid counting twice.

How do I read the JSON response?

Successful response data and request_id; failures return error.code, error.message and request_id. Keep the error code and request_id to locate most issues.

For email, payment or deployment settings, see Support and troubleshooting.