Entitlements Namespace
What a license or account may do inside your app, separate from how long it lasts. Sell tiers, add-ons and packs of uses from one app and one build.
What an entitlement is
A license says who may run your app and until when. An entitlement says what that license or account can do once it is in. You name each one once per app under Dashboard → Settings → Entitlements, with a duration (or lifetime) and credits (or none), then pick it when you generate licenses or give it to licenses and accounts, and your app asks Atlas at runtime. Change a grant in the dashboard and the user gets the new answer within about 20 seconds. Same key, same build, no update.
Entitlements live inside the license. An expired or banned license cannot sign in, so it holds nothing.
Two kinds
| Feature | On or off. Use it for tiers and add-ons: pro, batch, api-access. A grant can carry an expiry, so an add-on can run out before the license does. | |
| Counter | A number of uses, spent by your app: exports at 50, scans at 5 on a trial. Atlas keeps the count per license or account and refuses to go below zero, even when two copies of your app spend at the same moment. |
What people use them for
- Tiers in one app. Define
pro. Basic keys carry nothing, Pro keys carry it, and your app checksHas("pro"). Upgrading a customer is one click on their license; they keep their key and do not reinstall. - Add-ons on their own clock. Give a one-year license a
batchfeature that expires after 30 days. When it lapsesHas("batch")turns false. Giving it again renews it. - Limits on a trial. Trial keys get
scansat 5. Spend one per scan and show how many are left. A paid key gets the same counter with a bigger quota, or none. - Packs of uses. Sell 50 exports as a counter. When the customer buys more, give the same entitlement again with the new quota. It replaces the quota and keeps the count already used; tick reset usage to start again from zero. On account sign-in you can also sell the pack as a key: generate it with
exports:50, and when the customer redeems it withAccount.Redeemthe 50 are added to what the account holds.
In your app
Check a feature with Has. Show a counter with Remaining. Spend with Consume right before the work, not at startup, so a crash after the spend costs one use at most.
// A PDF tool: "pro" unlocks the batch tool, "exports" is a pack of 50.if (Atlas::Entitlements::Has("pro")) { ui::ShowBatchTool();} long long left = Atlas::Entitlements::Remaining("exports"); // -1 no limit, 0 none, else what is leftui::SetExportLabel(left < 0 ? "Unlimited exports" : std::to_string(left) + " exports left");ui::EnableExport(left != 0); // On the click, spend first and work second.if (Atlas::Entitlements::Consume("exports", 1)) { ExportPdf();} else { ui::ShowMessage(Atlas::Data::GetErrorMessage()); // "Nothing left of exports"}Which call to trust
| Has | Read once, then your code branches on it. Good for showing and hiding. A patched client can answer yes to itself. | |
| Remaining | The same kind of read, for labels and for greying out a button. Never the thing that stops a spend. | |
| Consume | Enforced by the server: it checks the count and deducts in one step, tied to the license or account. Reinstalling, a second PC or a patched client cannot make it spend what is not there. |
For a feature that must not leak, keep the valuable part (a file, a variable) on the server and fetch it only after the check. A feature flag alone is a gate in your own code.
Has
Hasbool Has(const std::string& key);key, the grant has not expired, and for a counter something is left.| Name | Type | Description |
|---|---|---|
key | string | The entitlement key from the dashboard. |
boolWhether the entitlement is usable right now.Remaining
Remaininglong long Remaining(const std::string& key);-1 means held with no limit (a feature, or a counter with no quota); 0 means not held, expired or used up.| Name | Type | Description |
|---|---|---|
key | string | The entitlement key. |
int64The amount left, -1 or 0.Consume
Consumebool Consume(const std::string& key, int amount = 1);amount (1 to 1,000,000) from a counter. The server does the arithmetic, so concurrent calls can never overspend. Returns false when refused; Data.GetErrorMessage() says why: nothing left, expired, not held, or not a counter.| Name | Type | Description |
|---|---|---|
key | string | The counter's key. |
amountoptional | int | How much to spend. Default 1. |
boolTrue when the spend was recorded.List and Refresh
Liststd::vector<std::string> List();string[]The keys, sorted.Refreshbool Refresh();boolWhether the server answered.Giving them out from a store
The license generator, in the dashboard and through an API token, takes an entitlements list. Each item is a key, then an optional quota after a colon, then optional days until expiry after a second colon: pro is a feature, exports:50 a counter of 50, batch::30 a feature that lapses in 30 days. An unknown key stops the whole request, so nothing is created half-way.
curl -X POST "https://atlassecurity.site/api/v1/apps/<appId>/licenses.generate" \ -H "Authorization: Bearer atlas_ik_..." -H "Content-Type: application/json" \ -d '{"count":1,"duration":365,"duration_type":"days","entitlements":"pro,exports:50,batch::30"}'