Skip to main content

Per-seat billing

With the per-seat model, your customer pays depending on how many seats they use, the amount they pay per seat is fixed. This makes it easy for them to understand their costs and budget accordingly. They can assign or unassign seats to grantees as they see fit, and the amount they are charged is automatically adjusted to match the number of seats active during the cycle.


Taking payments

To receive payment for your subscription, you'll need to create a Stripe checkout. Here, a customer can add their bank card details and upon successful checkout the subscription will be created. The next payment will occur based on the plan's interval length.

info

The first seat will be assigned to the granteeId provided - the rest will be unassigned.

import { getCheckoutLink } from '@salable/js'

const { checkoutUrl } = await getCheckoutLink({
apiKey: 'your-salable-api-key',
planUuid: 'your-salable-plans-uuid',
successUrl: 'https://your.app/payment-success'
cancelUrl: 'https://your.app/payment-cancelled',
granteeId: 'your-grantees-id',
owner: 'your-grantees-organisation-id',
});
OptionDescriptionRequired
successUrlThe url to redirect a customer after a successful checkout.
cancelUrlThe url to redirect a customer if they cancel the checkout.
granteeIdThe ID of the grantee which will be assigned to the first seat of the subscription, for example the user ID or a board ID. If the subscription is per-seat all additional seats created will be unassigned.
ownerThe ID of the customer's organisation.
currencyThe shortname of the currency to be used in the checkout. Default - plan's product default currency.
quantityThe amount of seats to create on the subscription after checkout. The plan's minimum and maximum limits cannot be exceeded. Default plan's minimum seat limit.

Create subscription

Creates a subscription without a payment.

tip

If you'd like to receive payment for a subscription, create a checkout link.

import { Salable } from '@salable/node-sdk';
const salable = new Salable('your-salable-api-key', 'v2');

const subscription = await salable.subscriptions.create({
planUuid: 'your-plan-uuid',
owner: 'orgId_1234',
granteeId: 'userId_1',
});

License check

Check whether a grantee can perform an action in your system. Feature values, capabilities, and plan names that belong to your user are checkable. If your grantee has multiple subscriptions, everything they have access to will be returned in the response.

import { getGrantee } from '@salable/js';

const { hasCapability } = await getGrantee({
apiKey: 'your-salable-api-key',
productUuid: 'your-products-uuid',
granteeId: 'your-grantees-id',
});

// Check for a capability
const isUserLicensedToPerformAction = hasCapability('acme-inc-whitelabelling');
// or a feature
const isUserLicensedToPerformAction = hasCapability('csv-export');
// or a plan
const isUserLicensedToPerformAction = hasCapability('pro');

Get seats

Get the list of seats that are on the provided subscription. One common usage of this data is to show your users the list of people on their team. Seats that have a status of CANCELED are not included in the response. The response uses cursor pagination.

import { Salable } from '@salable/node-sdk';

const salable = new Salable('your-salable-api-key', 'v2');
const seats = await salable.subscription.getSeats('your-subscription-uuid');

Get seat count

Obtain the aggregate count of seats, as well as the amount that are assigned or unassigned. This data can be used in many ways, one common usage is to show your users how many of their remaining seats are available to be filled. Seats that have a status of CANCELED are ignored in the count.

import { Salable } from '@salable/node-sdk';

const salable = new Salable('your-salable-api-key', 'v2');
const count = await api.subscriptions.getSeatCount('your-subscription-uuid');

Add seats

All seats created are unassigned by default. You can assign seats after they have been added to the subscription.

import { Salable } from '@salable/node-sdk';

const salable = new Salable('your-salable-api-key', 'v2');
await salable.subscriptions.addSeats('your-subscription-uuid', {
increment: 2,
});

Remove seats

Only unassigned seats can be removed.

danger

If you are receiving payment for your subscription, do not modify subscriptions directly through Stripe. Always manage them through the Salable API/SDKs to avoid issues.

import { Salable } from '@salable/node-sdk';

const salable = new Salable('your-salable-api-key', 'v2');
await salable.subscriptions.removeSeats('your-subscription-uuid', {
decrement: 2,
});
caution

Ensure that the number of seats being removed doesn't take the number of active seats below the minimum set on the plan.

Update seats

Manage seats on a subscription and which grantees are seated in them.

Assign seat(s)

If a seat has a granteeId of null it is considered unassigned. To assign an unassigned seat, set the type to assign and the granteeId to the new value. An available empty seat on the subscription will then be assigned to the new granteeId. If there are no empty seats, the request will be rejected.

import { Salable } from '@salable/node-sdk';

const salable = new Salable('your-salable-api-key', 'v2');
await salable.subscriptions.manageSeats('your-subscription-uuid', [
{
type: "assign",
granteeId: "your-new-grantee-id"
},
// You can perform multiple actions by passing in multiple objects.
]);

Unassign seat(s)

For a seat to be unassigned, its granteeId must be set to null. To unassign a seat, set the type to unassign and the granteeId to the ID of the grantee you want to unassign from the seat.

import { Salable } from '@salable/node-sdk';

const salable = new Salable('your-salable-api-key', 'v2');
await salable.subscriptions.manageSeats('your-subscription-uuid', [
{
type: "unassign",
granteeId: "grantee-id-to-be-unassigned"
},
// You can perform multiple actions by passing in multiple objects.
]);

Replace grantee(s)

Replacing a seat's granteeId is moving the seat from one grantee to another. To replace a seat's grantee, set the type to replace, the granteeId to the ID of the grantee you want to unassign from the seat, and set newGranteeId to the ID of the new grantee of the seat.

import { Salable } from '@salable/node-sdk';

const salable = new Salable('your-salable-api-key', 'v2');
await salable.subscriptions.manageSeats('your-subscription-uuid', [
{
type: "replace",
granteeId: "grantee-id-to-be-replaced",
newGranteeId: "new-grantee-id"
},
// You can perform multiple actions by passing in multiple objects.
]);
import { Salable } from '@salable/node-sdk';

const salable = new Salable('your-salable-api-key', 'v2');
await salable.subscriptions.manageSeats('your-subscription-uuid', [
{
type: "replace",
granteeId: "current-grantee-id",
newGranteeId: "new-grantee-id"
}
]);

Upgrade and downgrade

Changing the subscription's plan will grant all its seats access to different features. Seats that have a status of CANCELED will not be updated. When changing plan the quantity of the subscription may change to ensure its in the new plans minimum and maximum seat count limits. For example, if a subscription has three seats and moves to a new plan with a minimum of five seats, two extra unassigned will be created on the subscription to meet the new minimum. If a subscription has eight seats and moves to a new plan with a maximum of six seats, two unassigned seats will be canceled to not exceed the new plan's maximum. If there are not enough unassigned seats to cancel the request will be rejected.

import { Salable } from '@salable/node-sdk';

const salable = new Salable('your-salable-api-key', 'v2');
const changeSubscriptionPlan = await salable.subscriptions.changePlan(
'your-subscription-uuid',
{
planUuid: 'the-new-plan-uuid',
proration: 'create_prorations', // optional. see table below for more options
}
);
info

Proration options are only applicable on subscriptions that have taken a payment.

ValueDescription
create_prorationsKeeps the subscription's billing cycle start/end date and refunds for unused time on the previous plan. The new cost of update will not be reflected until the next billing cycle. For the cost the be reflected immediately use always_invoice.
always_invoiceImmediately reflects the cost change with an invoice.
noneDisables proration behaviour

Cancel subscription

You can cancel a subscription with its associated subscriptionUuid. All the subscription's associated seats will also be canceled.

import { Salable } from '@salable/node-sdk';

const salable = new Salable('your-salable-api-key', 'v2');
await salable.subscriptions.cancel('your-subscription-uuid', { when: 'end' });
info

The when query parameter represents when you want the subscription to cancel.

WhenDescription
nowImmediately cancels the Subscription. If the Subscription is paid, the customer will be immediately invoiced.
endCancels the Subscription at the end of its cycle. To undo this you can reactivate the subscription. If the Subscription is paid, the customer will be invoiced at the end of the cycle.

Demos

Per-seat billing in Next.js
Miro app with per-board billing