Catalog
Plans, entitlements, add-ons and incentives decide what each account can use. You edit them under Catalog in the app nav, and your app sees the change on its next access check.
The four record types are explained in Core concepts. This page covers where you edit each one, how they attach to accounts, and the order the API applies them in. Each list page has a help button (How Plans Work, How Entitlements Work and so on) that opens a short explainer.
Entitlements
Catalog → Entitlements (/apps/[appId]/entitlements) lists the features and limits you gate. Click New entitlement and fill in:
- Name
- Shown in the dashboard and returned to the SDK as name.
- ID
- What your code checks, such as
ai_credits. IDs can't be changed after creation. - Type
- Usage (
usage) is counted against a limit, such as projects or credits. Feature flag (boolean) is on or off, such as SSO or PDF export. - Description
- Optional. What the entitlement gives access to or limits.
An entitlement has no limit of its own. Limits are set where you attach it: on a plan, an offer or an incentive. The list shows where each entitlement is used, and you can filter it to Usage or Feature flags. Changing the type of an entitlement that plans already use keeps their existing limits.
overage: { mode: "block" } with PATCH /apps/:appId/entitlements/:id. See the Endpoint reference.Plans
Catalog → Plans (/apps/[appId]/plans) lists every plan with its price, limits, add-ons and account count. Every account is on exactly one plan.
Create the plan
Click New plan. Give it a name and ID, an optional description, and turn on Free plan if accounts on it don't pay. The plan page opens.
Attach entitlements and add-ons
On the Access tab, pick an entitlement under Add entitlement… and enter a limit. Leave the limit empty for unlimited. Feature flags take no limit. Click any limit later to change it. Add add-ons the same way below.
Set the price
On the Pricing tab, fill in the pricing card and click Publish pricing card. See The pricing editor.
The plan page has four tabs and a side panel:
- Access
- The entitlements with their limits, and the add-ons included.
- Pricing
- The Free plan switch and the pricing card.
- Metadata
- Key/value pairs your app reads at runtime.
- Accounts
- Accounts on this plan, paginated.
- Side panel
- Details (edit the name and description in place), Checkout link for a plan that isn't free and has a price on its pricing card, an Internal note for your team, and SDK response: what
GET /namespaces/:id/planreturns for a new account on this plan.
Duplicate copies the limits, add-ons, metadata and pricing card into a new plan. Accounts stay on the original. Delete plan asks you to type the plan ID when accounts are on it, because their access checks fail until you move them to another plan.
The pricing editor
The Pricing tab edits what GET /apps/:appId/plans/pricing returns for your pricing page. A live preview of the card sits on the right, with a Monthly/Yearly toggle for subscriptions.
- Free plan
- Accounts on it don't pay. It shows as Free on your pricing page and is never offered as a paid upgrade. The SDK sees it as isFree.
- Title and Description
- The card's heading and subheading.
- Pricing
- Subscription takes a Monthly price and a Yearly price. One-time takes a single Price. Both take a Currency.
- Featured
- Highlights the plan on your pricing page.
- Benefits
- Bullet lines for the card. Drag to reorder.
Publish pricing card saves it (the button reads Save changes once a card exists). Remove card takes the plan off GET /plans/pricing. The card's prices are also the list prices that offers and plan checkout links sell at.
Metadata
The Metadata tab stores key/value pairs on the plan, such as max_projects, badge or stripe_price_id. Numbers, booleans and JSON are parsed, so the SDK gets real types. Each key is one of:
- Public
- Returned by
GET …/plan, so your frontend can read it. - Private
- Stripped from
…/plan. Your backend reads it fromGET …/full-planwith the secret key.
Add-ons
Catalog → Add-ons (/apps/[appId]/addons) holds optional extras, such as an extra storage pack or white-label branding. An add-on is a name, an ID and a description. It does nothing until you attach it: on a plan's Access tab, an incentive's Overrides tab, or an offer. Your app receives the IDs in the addons array of the access response.
An account can also own add-ons directly, for example after buying an order bump. The dashboard has no control for this; use POST /apps/:appId/namespaces/:id/addons.
Incentives
Catalog → Incentives (/apps/[appId]/incentives) holds overrides you apply to single accounts: a promo, a partner deal, a beta perk or a win-back offer. An incentive changes what an account gets without changing its plan.
- Overrides tab
- Entitlements override the limit from the account's plan, or grant the entitlement if the plan doesn't include it. Add-ons are granted on top of the plan's. Impact by plan shows what accounts on each plan end up with.
- Accounts tab
- Every account that has this incentive, with its plan.
- Apply to an account
- A side panel to search accounts, apply the incentive, or remove it from an account.
- Apply from your backend
- A snippet for applying it from your server with the secret key, for example after a promo code checkout.
An account has at most one incentive. Applying a new one replaces the old one. Removing an incentive never touches usage counters or the account's plan.
Accounts
Customers → Accounts (/apps/[appId]/accounts) lists your customers. The API calls them namespaces. You can search by name or ID and filter by plan or incentive. Your app usually creates accounts, but New account creates one by hand: an Account ID (the user or team ID from your product), an optional name, a plan and an optional incentive. You need at least one plan first.
An account page has four tabs and a side panel:
- Access
- The resolved result: usage against each limit, every feature flag and whether the account has it, and add-ons from the plan or the incentive.
- Activity
- Recent usage calls for this account (add, remove, amount).
- Analytics
- Usage by entitlement over a period.
- API response
- A curl command and the live response, for
/planwith the public key or/full-planwith the secret key. - Side panel
- Details and a Usage simulator that sends the same usage calls your app makes.
Changing one account
There is no per-account entitlement editor. To change what one account gets, either move it to another plan or apply an incentive:
- Change plan in the page header opens a dialog that lists what changes (limits, features and add-ons) before you confirm.
- The … menu has Apply incentive… (or Change incentive…), Remove incentive, Rename…, Copy account ID and Delete account.
Both take effect on your app's next access check.
How access is resolved
When your app asks for an account's access (GET /apps/:appId/namespaces/:id/plan or /full-plan), the API builds the answer from up to three layers. A later layer overrides an earlier one for the same entitlement ID:
- The plan: its entitlements and limits.
- Offer extras: the extra entitlements from the offer the account bought through. They apply while the subscription is active, and stop when the intro price ends or the set duration passes, depending on how the offer was configured.
- The incentive: its overrides, until the incentive's expiry passes if it has one.
Add-ons are merged from all three layers plus the ones the account owns. Each entitlement comes back with its limit, current usage, what's left and whether the account can use it.
| Layer | ai_credits limit |
|---|---|
| Pro plan | 2,500 |
| Offer extra (during the discount) | 5,000 |
| Incentive | Unlimited |
| Result | Unlimited, until the incentive is removed. Then 5,000 while the discount lasts, then 2,500. |
The API reads the catalog on every request. Nothing about plans, limits or incentives is compiled into your app, so edits in the dashboard reach your users on their next check, with no deploy.
{
"plan": { "id": "pro", "name": "Pro", "isFree": false, "meta": {} },
"incentive": "black_friday_2026",
"offer": "spring_sale",
"addons": ["ai_boost"],
"entitlements": [
{ "id": "ai_credits", "type": "usage", "usage": 1200, "max": null, "left": null, "can": true },
{ "id": "export_pdf", "type": "boolean", "usage": 0, "max": null, "left": null, "can": true }
]
}The React SDK reads this response for you. See Access and entitlements.