Custom Attributes

Custom attributes let you attach your own data to products, licenses, users, organizations, resellers, activations, and trial activations. You define each attribute once, with its name, whether it is required, a default value, and who can see or change it. Cryptlex then validates every value against that definition, lets you filter lists by it, shows it in the portals you allow, and makes it readable in your app.

Typical uses are storing an order or CRM reference on a license, a region or tier on an organization, recording that a customer accepted your EULA, or collecting details about the machine an activation runs on.

Defining a custom attribute

Create custom attributes in the admin portal under Settings -> Custom Attributes, or through the Web API.

Custom attribute properties

PropertyDescription
NameThe key you use to set, read, and filter the attribute in the Web API and in your app. It must be unique per resource type and cannot be changed after creation.
Display NameThe label shown to users in the customer and reseller portals. Unlike the name, you can change it at any time.
Resource TypeThe resource the attribute belongs to: product, license, user, organization, reseller, activation, or trial-activation. It cannot be changed after creation.
Data TypeThe type of the value. Currently only string is supported.
ProductsFor license, activation, and trial activation attributes, the products whose licenses or activations carry the attribute. See Linking products.
RequiredWhether a value must be provided when the resource is created. See Required attributes and default values.
Default ValueThe value stored when none is provided.
Application Access, User Access, Organization Access, Reseller AccessWho can read or change the value. See Access levels.
ArchivedRetires the attribute without deleting its values. See Archiving and deleting custom attributes.

Linking products

License, activation, and trial activation attributes apply only to the licenses and activations of the products you link to them. An attribute with no linked products applies to nothing, so a required attribute added for one product never affects the licenses of your other products.

You can link more products at any time. Unlinking a product is not allowed once that product has any licenses or trial activations, since those resources already carry values for the attribute.

Required attributes and default values

Required attributes and default values are applied when the owning resource is created:

  • If a required attribute has no default value and the create request does not provide a value, the request fails.
  • Every applicable attribute the request does not provide is stored with its default value, or an empty string if it has none. This way every resource carries its full set of attributes.

Updating a resource never fails because of a required attribute.

When you create an attribute, link more products to it, or unarchive it, Cryptlex also adds the default value to existing products, licenses, users, organizations, and resellers that don't have a value yet. Existing activations and trial activations receive the default value on their next server sync. Changing the default value later does not change values that are already stored.

Access levels

Each attribute has an access level for each audience, set once on the definition:

  • none: the audience cannot see the attribute.
  • read: the audience can see the value.
  • read-write: the audience can see and change the value.
AccessAudience
Application AccessYour app, through LexActivator or the activation endpoints of the Web API. With read access the value is included in the signed activation response; with read-write access your app can also set it.
User AccessEnd users in the customer portal.
Organization AccessOrganization admins in the customer portal.
Reseller AccessReseller admins in the reseller portal.

Admins in the admin portal, and Web API calls made with an access token that has the scopes for the owning resource, always have full access.

Not every level is allowed for every resource type. For example, product data is shared by all your customers, so only your app can read it, and activation attributes are always written by your app:

Resource typeApplicationUserOrganizationReseller
LicenseUp to read-writeUp to read-writeUp to read-writeUp to read-write
ProductUp to readnonenonenone
UserUp to readUp to read-writeUp to read-writeUp to read-write
OrganizationUp to readnoneUp to read-writeUp to read-write
ResellernonenonenoneUp to read-write
ActivationAlways read-writeUp to readUp to readUp to read
Trial activationAlways read-writenonenonenone

Setting values

From the admin portal or the Web API

Set values on the resource itself when you create or edit a product, license, user, organization, or reseller in the admin portal, or through its customAttributes property in the Web API. Each name must match a custom attribute defined for that resource type (and, for licenses, linked to the license's product). Setting a value overwrites the previous one; to clear a value, set it to an empty string. Values of archived attributes cannot be changed.

From your app

Your app can set values on its license, activation, or trial activation, as long as the attribute grants read-write application access. Activation and trial activation attributes always do; license attributes do only if you allow it, which is useful for things like recording EULA acceptance against the license.

With LexActivator, call SetCustomAttribute() with the resource type, name, and value before activating, or at any time after. LexActivator sends the values with the next activation or server sync request:

SetCustomAttribute(LA_RESOURCE_TYPE_ACTIVATION, "device_env", "production");
SetCustomAttribute(LA_RESOURCE_TYPE_LICENSE, "eula_accepted", "true");
ActivateLicense();

The resource type must be one of LA_RESOURCE_TYPE_LICENSE, LA_RESOURCE_TYPE_ACTIVATION, or LA_RESOURCE_TYPE_TRIAL_ACTIVATION. Setting a license attribute that does not grant your app read-write access fails with LA_E_CUSTOM_ATTRIBUTE_ACCESS_DENIED, either immediately or, if LexActivator does not yet know the attribute's access level, on the next server sync.

If you license via the Web API directly, send the values in the customAttributes array of the POST /v3/activations or PATCH /v3/activations/:id request, with a resourceType of license or activation for each entry:

"customAttributes": [
{ "name": "eula_accepted", "resourceType": "license", "value": "true" },
{ "name": "device_env", "resourceType": "activation", "value": "production" }
]

Trial activation requests take plain name and value pairs, since there is no license to route the value to.

A few rules apply to values your app sets:

  • Required activation and trial activation attributes must be provided when the activation is created, unless they have a default value; otherwise, the activation fails. Required license attributes are not enforced during activation, so adding one never breaks your deployed installations.
  • If any value in the request is invalid, or your app does not have read-write access to it, the whole activation request fails.
  • When a license attribute value actually changes, Cryptlex fires the license.updated webhook. Resending an unchanged value on every sync does not.

Reading values in your app

Values of attributes that grant your app read or read-write access are included in the signed activation response, and are refreshed on every server sync. Archived attributes are never included.

With LexActivator, read a single value with GetCustomAttribute(), or all values of a resource type with GetCustomAttributes(). Pass one of the following resource types:

Resource typeReturns attributes of
LA_RESOURCE_TYPE_PRODUCTThe product. Available for both license and trial activations.
LA_RESOURCE_TYPE_LICENSEThe activated license.
LA_RESOURCE_TYPE_USERThe user the license is assigned to.
LA_RESOURCE_TYPE_ACTIVATIONThe current activation.
LA_RESOURCE_TYPE_TRIAL_ACTIVATIONThe current trial activation.
char region[1025];
if (GetCustomAttribute(LA_RESOURCE_TYPE_LICENSE, "region", region, 1025) == LA_OK)
{
printf("Region: %s", region);
}

An attribute your app cannot read returns LA_E_CUSTOM_ATTRIBUTE_NOT_FOUND, as if it did not exist. A value your app set with SetCustomAttribute() is returned only after the server has accepted it on the next activation or server sync.

Archiving and deleting custom attributes

Once any resource of its type exists, a custom attribute holds stored values and cannot be deleted. Archive it instead. An archived attribute:

  • Keeps its existing values, visible only to admins in the admin portal and the Web API.
  • Is hidden from the customer and reseller portals and from your app.
  • Rejects new values, and is no longer required or given a default on new resources.
  • Cannot be edited until you unarchive it.

Unarchiving an attribute makes it active again and adds its default value to existing resources that don't have one yet.

License metadata for integrations

Besides custom attributes, each license can hold up to five metadata fields. They are meant for integrations that need to store their own reference on a license, such as the subscription ID from your payment gateway. The Stripe, Paddle, and FastSpring integrations use them this way.

License metadata:

  • Can only be set through the Web API, using the metadata property when you create or update a license.
  • Cannot be used to filter licenses.
  • Is available on licenses only.

For any other data you want to store on a license, use a custom attribute.

Limits

You can define up to 20 custom attributes per resource type. Enterprise plans can have a custom limit. Each license can also hold up to five metadata fields.

License TemplatesMeter Attributes
Last updated: