Browse the library
Documentation libraryLicensing
End users
End users are the accounts (a username and a password) your customers use to sign in to your software. Each account belongs to one app and is linked to a license; you add, find, ban, reset and delete them right in the dashboard.
6 min read
When an app has end users
Accounts only work when the app's sign-in mode is Account or Account + license key. You pick the mode under Licensing & releases › Sign-in & license plans, in the Sign-in mode card. In License key mode the software uses activate(key) and trial() only, and register() and login() are refused with mode_not_allowed. Each mode is covered in Sign-in modes and trials.
A few ground rules:
- A username is unique within an app, 3 to 64 characters long, and may contain ASCII letters, digits, dots, dashes and underscores. Sign-in matches it exactly, so it is case-sensitive.
- A password is 8 to 128 characters and is only ever stored as an Argon2id hash.
- Term, machines and entitlements come from the license the account is linked to, not from the account.
Where accounts come from
| Source | The account's license |
|---|---|
Your software calls register() with a key | That key's license |
Your software calls register() without a key | A license created automatically from the default plan, listed under Licenses as ACCT-… |
| You click Add user in the dashboard | The key you enter, or no license if you leave it empty |
Seller API (POST /apps/{appId}/users, scope users:write) | Same as the dashboard |
The default plan is the one with Default for new keys and free accounts turned on under Sign-in & license plans. If the app has no default plan, the automatic license has no expiry, allows 1 machine and grants no entitlements.
Viewing and finding users
Open End users › Users (or press G then U while an app is open). The table shows Username, Status (Active or Banned), Email, Last sign-in and Created, newest first. The Search users… box matches part of a username or email, ignoring case. Rows load 50 at a time; click Load older for more.
To see which account holds a key, open that license under Licensing & releases › Licenses: the Linked users section lists the username and its last sign-in.
Adding a user from the dashboard
- Go to End users › Users and click Add user.
- Enter a Username and a Password (at least 8 characters).
- Email is optional.
- In License key, paste an existing key of this same app if the account should work right away.
- Click Create.
The dialog shows an error when the name exists (Username already taken), when the key is not in this app (License key not found in this app) or when your plan is full (Your plan allows … end users). A new account shows Never under Last sign-in until its first sign-in.
Linking to a license
From the software side, a license links to one account only: registering or upgrading with a key that already has an owner returns license_already_registered. If the key was never used, its term starts at the first registration or sign-in.
In Account + license key mode, people sign up for free and upgrade later with redeem(key). The account keeps its name, password and current machine and moves to the new license; the old session ends and the software receives a new one. The automatic free license it started on is revoked, while a real key it held before is left as it was. Redeeming the key already in use returns already_redeemed.
The dashboard has no action to change a created account's username, email or license.
To send settings to one person, use Integration › Variables with the One user scope; the account ID (usr_…) comes in the user.created webhook payload and the Seller API. See App variables.
Banning and unbanning
- In End users › Users, click the ⋯ button at the end of the row.
- Choose Ban.
The status turns Banned and every open session of the account ends at once. Running software gets session_expired on its next request (usually the heartbeat), and the next sign-in with the right password gets user_banned. The license and its bound machines are left alone. Banning fires the user.banned webhook.
Unban sets the status back to Active. Ended sessions do not come back; the person simply signs in again.
Resetting a password
Clavis has no self-service "forgot password" flow for end users, so resets go through you:
- Click ⋯ on the user's row and choose Reset password.
- Enter the new password (at least 8 characters) and click Save.
Every open session of the account ends immediately, so each machine has to sign in again with the new password. Send it to your customer through your own support channel.
Deleting a user
Choose ⋯ › Delete. The account is removed right away, with no confirmation dialog and no undo. After that:
- The username is free again and the license can be linked to a new account.
- The license stays, including an automatic
ACCT-…license. Bound machines keep their slots on it. - Open sessions are not ended.
The user limit per plan
When your software registers an account or you add one in the dashboard, the platform counts the accounts that app already has (banned ones included) and compares the number with the End users limit of your workspace's plan:
- Registering from the software when full: refused with
user_limit. - Adding from the dashboard when full: the dialog shows an error and no account is created.
- Plans with soft limits never block.
| Plan (default settings) | End users | At the ceiling |
|---|---|---|
| Basic | 500 | New accounts are blocked |
| Premium | 50,000 | Soft limit, nothing is blocked |
The numbers that apply to your workspace are under Account & organization › Plan & usage, next to the total number of users across all your apps. Deleting accounts nobody uses gives the room back. See Basic, Premium and limits and pricing.
Signing in from your software
With the JavaScript SDK, registering and signing in return the same signed answer: the session, the license, its entitlements and your variables. A successful registration means the person is already signed in on that machine.
import { ClavisClient, ClavisError } from "@clavisauh/sdk";
const clavis = new ClavisClient({
baseUrl: "https://api.example.com",
appId: "app_…",
appPublicKey: "…",
device, // this machine's identity, see the Quickstart
});
const { app } = await clavis.init();
if (app.loginMode === "key") showKeyForm();
try {
// First run: key may be null (a free account on the default plan)
const grant = await clavis.register(key ?? null, username, password, email);
// Later runs: const grant = await clavis.login(username, password);
if (clavis.has("export_pdf")) enableExport();
showExpiry(grant.license.expiresAt);
} catch (err) {
if (!(err instanceof ClavisError)) throw err;
showError(err.code); // map the code to your own message
}
// Account + license key mode: upgrade the signed-in account
await clavis.redeem(paidKey);
Every sign-in binds the machine to the account's license, so the machine limit is per license (see Devices, HWID and transfers). clavis.logout() ends the current session.
Common error codes:
| Code | Meaning |
|---|---|
invalid_credentials | Wrong username or password. A wrong key at registration returns this too |
username_taken | The username already exists in this app |
license_already_registered | The key is linked to another account |
user_limit | The app has reached the plan's account limit |
user_banned | The account is banned |
no_license | The account has no linked license |
too_many_attempts | 20 failures from one IP within 15 minutes; wait and try again |
device_limit | The license is already on its maximum number of machines |
Every user.register, user.login and user.redeem is recorded under App security › Activity log, with the reason when it was refused.