Thank you for reaching out.
The GetUserLicenses() function retrieves user licenses by making a network request to the server. Since the license count is not known prior to this call, you will need to allocate a buffer with a reasonable maximum size beforehand.
After a successful call, you can determine the actual number of licenses by iterating through the array and checking when the key field becomes empty. This indicates you have reached the end of valid licenses.
If the function returns LA_E_BUFFER_SIZE, your buffer was insufficient, and you should increase the size accordingly.
Thank you for reaching out!
The time displayed on the Activations page in the Admin Portal is shown in your local timezone, based on the system from which you are viewing the portal. On the backend, all timestamps are stored in UTC, and the frontend automatically handles the conversion to your local timezone for display purposes.
]]>I just have a small question - on the Activations screen in the portal, when we click on an activation we can see the “Last Synched” time. Is this time in the local time of our computer (viewing the portal) or of the computer hosting the license server (it is in a different time zone to us).
Thanks very much.
Kind Regards,
Helen
Thank you for reaching out.
Please refer to the following documentation link for relevant details: License Templates | Allowed Activations
For clarity, if allowedActivations of a license key is set to 2, the license can be activated on a maximum of 2 machines. If a third machine attempts activation, it will fail, and our SDK will return LA_E_ACTIVATION_LIMIT (error 58).
Node-locked by nature are permanently locked to the machine where they are activated. To free an activation seat, the license key must be deactivated on one of the existing machines. This can be done from the application by calling DeactivateLicense(), via the v3/activations/{id}/deactivate API endpoint, from the Activations page in the admin portal, or by the end user through the customer portal.
Once an activation slot is freed, the license can be activated on the new machine using the same license key.
]]>If I set this to 2, does that mean the license can be used concurrently on machine A and B? What happens if I try to use it on machine C? Will it be blocked automatically, or will it release machine A or B? If it is blocked, can I release it via the API on machine A or B to allow machine C?
]]>From a technical/API-design perspective I can see two possible rationales for requiring licenseId:
licenseKey (which is also consistent with other endpoints).licenseId is the natural handle.That said, for the “service laptop / customer-side activation tool” scenario this still creates friction, because it forces an additional lookup step (key → id) and therefore either:
licenseId alongside the licenseKey, orWould you consider one of the following to support this pattern more cleanly?
licenseKey as an alternative input (server resolves to licenseId internally), orHappy to align with your recommended best-practice pattern, but right now licenseId as a hard requirement makes the decoupled offline activation tooling noticeably harder to implement cleanly.
Best regards,
Dominik
The rationale behind requiring the licenseId for the CreateOfflineActivation endpoint is tied to how this flow is designed to be used. This endpoint is primarily invoked from the Admin Portal or Customer Portal, where the licenseId is already known.
When the same endpoint is used from another interface, it is assumed that the system performing the offline activation can access the license details using the licenseKey. This intent explains why this endpoint requires a licenseId rather than a licenseKey.
I hope this provides clarity.
]]>thanks for the clarification. I have one follow-up question regarding the API design.
For the CreateOfflineActivation endpoint, a licenseId is required, whereas for the online activation flow the licenseKey alone is sufficient.
In offline scenarios, where the activation is intentionally decoupled from the device and performed on a separate, connected system (e.g. a service engineer laptop or a customer backend), this creates an additional hurdle:
licenseId has to be shared alongside the licenseKey, orlicenseId from the licenseKey.Both options somewhat weaken the otherwise clean separation between the offline device, the license key handed to the customer, and the activation tooling.
Could you share the rationale behind requiring licenseId for offline activation?
Are there recommended patterns to handle this securely and conveniently in air-gapped or customer-side activation workflows?
Thanks in advance,
Dominik
There are no specific permissions required for this endpoint. A valid access token is sufficient to use it.
Best regards,
Anees
it looks like that authorization is necessary for this endpoint. Can you please comment on which permissions the access token needs to have to create an offline activation response?
Thanks,
Dominik
Thank you for reaching out.
The GetErrorMessage function does not appear to be part of our SDK, as it does not pertain to any functionality we provide. Could you please clarify which specific function you are referring to, or share the relevant context or code snippet so that we can better assist?
Yes, you can automate the offline activation workflow using the Create an Offline Activation API endpoint to generate the offline activation response.
]]>Since our devices are not connected to the internet, we are looking for a way to make the offline activation flow as convenient as possible for users and service engineers.
One option would be a small internal tool running on a connected laptop (e.g. a service engineer laptop) that:
From the documentation, it appears that creating an offline activation response is only possible via the admin portal or customer portal, and that this step is not exposed via the Web API.
Is this correct, or am I missing an API-based approach to automate the offline activation response generation?
Are there any recommended or supported alternatives for automating this workflow?
Thanks in advance,
Dominik
As long as the machine fingerprint remains unchanged, calling ActivateLicense() again on the same machine will update the existing trial activation details, such as the expiration date, rather than creating a new trial activation.
Additionally, as previously communicated, a new function is planned in v5 that will just update the trial activation details, such as an extended expiry date. At this time, there is no confirmed ETA for its availability.
For any further assistance, please feel free to reach out to our support channel at [email protected].
Kind regards,
Anees
After updating the Expiration Date of a trial activation on the server side, call the ActivateLicense() function on the client side to have the changes reflected locally.
Once done, you can call GetTrialExpiryDate() to retrieve the updated trial expiry date timestamp.
The ability to directly update the expiresAt of a trial activation has now been added. For reference, here is the relevant endpoint: https://api.cryptlex.com/v3/trial-activations/{id}/expires-at. You can also update the expiration date through the admin portal by using the Actions menu of a trial activation.
If you need any further assistance, please contact us at [email protected] and we will be glad to help.
]]>Thank you for reaching out.
With longer sync intervals, the program will continue to run until the next serverSync occurs, even if the activation is deleted from the portal. This could potentially be misused, as the application will not immediately receive the updated license status.
To mitigate this, we recommend either:
This ensures the application verifies its license status more frequently and reduces the risk of any unintended or unauthorized use.
]]>void setCryptlexDataFolder() {
#ifdef __APPLE__
// We can check from the HOME variable whether we are running from an app store app or not.
const char* home = std::getenv("HOME");
std::string home_str(home);
if (home_str.find("Library/Containers") != std::string::npos) {
// Running in an app store sandbox, need to set data folder
std::string data_dir = home_str + "/Documents/iConf/";
mkdir(data_dir.c_str(), 0755); // Create directory if it doesn't exist
int status = SetDataDirectory(data_dir.c_str());
log("Setting Cryptlex data directory to: %s", data_dir.c_str());
if (LA_OK != status) {
ShowDialog("App Store host detected. Failed to set Licensing data folder. Error: " + std::to_string(status));
}
} else {
// Running as a regular app, just stick with default location.
}
#endif
#ifdef _WIN32
// Do nothing, generally works by default
#endif
}
And I call it just before setProductData().
Kindly reach out to our support channel via [email protected]. We may need to share a debug build to investigate the issue in more detail.
]]>The host is indeed installed and running from the /Applications folder, and this user only has one account on his machine.
In the top half of the below screenshot, you’ll see their permissions for their Library and Application Support directories given by ls -ld
I’ve also had them run the command you offered and that’s in the bottom half of the below screenshot.
Do let me know if there’s something we can use to diagnose the fourth option of there being some sort of unusual setting or third party software. I’m thinking it’s probably the most likely, if you think these permissions shown by ls look about right. The user does say they’re not aware of any antivirus software on their computer.