Apps Installed into a Workspace
Count the integrations or apps a workspace installs against its plan, and sell more of them.
An app or integration installed into a workspace belongs to the workspace, so the workspace's plan decides how many it may hold. Declare a limit for it on your workspace plans, claim a slot when an app is installed and release it when it is removed. BuildBase keeps the count and refuses the install past the ceiling.
const res = await fetch(
`${serverUrl}/api/v1/public/workspaces/${workspaceId}/limits/installed-apps-per-workspace/claim`,
{
method: 'POST',
headers: {
'x-session-id': sessionId,
'Content-Type': 'application/json',
},
body: JSON.stringify({ resourceId: `app:${appId}` }),
}
);
if (res.status === 402) return showUpgrade(await res.json());
if (!res.ok) throw new Error('Could not install the app');
await installApp(workspaceId, appId);Before you start
Declare a LIMIT item installed-apps-per-workspace with "scope": "workspace", and give each workspace plan its value: 3 on a Team plan, -1
on a Business plan. The slug is yours to name; BuildBase does not reserve this
one.
Install and uninstall
Claim when the app is installed, with the app's id as the resourceId. Installing the same app twice is the same claim, so a retried request never takes a second slot. Release with the same resourceId when it is removed:
await fetch(
`${serverUrl}/api/v1/public/workspaces/${workspaceId}/limits/installed-apps-per-workspace/release`,
{
method: 'POST',
headers: {
'x-session-id': sessionId,
'Content-Type': 'application/json',
},
body: JSON.stringify({ resourceId: `app:${appId}` }),
}
);The member installing needs permission to record usage in the workspace, the same permission that claims any workspace limit. GET .../limits/installed-apps-per-workspace answers the ceiling, claimed and remaining for a "2 of 3 apps" line, and GET .../claims lists what is installed.
Count installs by claims only. If you also pass your own count as current to useLimit, every app counts twice.
Per project inside a workspace
Pass a partitionKey to count per project instead of per workspace: with a ceiling of 3, each project holds three apps.
{ "resourceId": "app:slack", "partitionKey": "project:42" }When your end users install
If the people installing are your customers' end users rather than the customer who pays, mark the item endUserBoundary. At the ceiling they get 403 CEILING_REACHED with no plan in the message, and you receive entitlement.ceiling_reached with the workspace, the slug and the count, at most once an hour per workspace, so your backend can tell the workspace's owner.
Selling more installs
A higher plan raises the ceiling, and so does an add-on: a recurring offer on the same limit sells install slots one at a time, without a plan change.
{
"slug": "extra-app-slots",
"name": "+2 app slots",
"shape": "recurring",
"items": [
{
"itemSlug": "installed-apps-per-workspace",
"itemKind": "limit",
"quantityPerUnit": 2,
"mode": "add"
}
],
"maxQuantity": 10,
"pricingVariants": [
{ "currency": "usd", "prices": { "monthly": 500, "yearly": 5000 } }
]
}A Team workspace with a ceiling of 3 that buys one unit can install five apps. The claim's 402 is the moment to offer it:
Note
usePurchaseAddOn, createAddOnPurchaseRedirectUrls and useLimit: Requires @buildbase/sdk 1.0.0 or later.
import {
createAddOnPurchaseRedirectUrls,
usePurchaseAddOn,
} from '@buildbase/sdk/react';
function MoreSlots({ workspaceId }: { workspaceId: string }) {
const { purchaseAddOn, loading } = usePurchaseAddOn(workspaceId);
return (
<button
disabled={loading}
onClick={() =>
purchaseAddOn({
offerSlug: 'extra-app-slots',
...createAddOnPurchaseRedirectUrls(workspaceId),
})
}
>
Add two more app slots
</button>
);
}The slots are charged on the workspace's own subscription, for the rest of the period now and then with every renewal. Cancel them and they keep counting until the end of the period already paid for.
A paid app. To charge for one app rather than for slots, declare a workspace-scope feature for it, such as app-salesforce-sync, sell it as a recurring offer that grants that feature, and check the feature before the install claims its slot. The app's buyers and a plan that includes it pass the same check.
A plan's limit plus any add-on units is the ceiling. Existing installs stay when the ceiling drops, because a plan changed or the add-on ended, and new installs are refused until the workspace is back under it.
Next steps
- Plans for users vs plans for workspaces - Every claim answer and its code.
- Add-ons - Offers, buying, cancelling and refunds.
- Webhooks -
entitlement.ceiling_reachedand the rest.