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.
The first seat will be assigned to the granteeId
provided - the rest will be unassigned.
- JS SDK
- Node SDK
- Fetch
- cURL
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',
});
// Don't forget to: npm install @salable/node-sdk
import { Salable } from '@salable/node-sdk';
const salable = new Salable('your-salable-api-key', 'v2');
const { checkoutUrl } = await salable.plans.getCheckoutLink('your-plan-uuid', {
successUrl: 'https://example.com/success',
cancelUrl: 'https://your.app/cancel',
granteeId: 'your-grantees-id',
owner: 'your-grantees-organisation-id',
});
const params = new URLSearchParams();
params.append("granteeId", "id-of-grantee");
params.append("owner", "id-of-the-grantees-organisation");
params.append("successUrl", "https://example.com/success");
params.append("cancelUrl", "https://example.com/cancel");
const response = await fetch(`https://api.salable.app/plans/your-plan-uuid/checkoutlink?${params}`, {
headers: {
"x-api-key": "your-salable-api-key",
version: "v2"
}
})
const checkout = await response.json();
curl
-XGET
-H 'x-api-key: your-salable-api-key'
-H 'version: v2'
'https://api.salable.app/plans/your-plan-uuid/checkoutlink?successUrl=https%3A%2F%2Fyour.app%2Fsuccess&cancelUrl=https%3A%2F%2Fyour.app%2Fcancel&granteeId=your-grantees-id&owner=your-grantees-organisation-id'
Option | Description | Required |
---|---|---|
successUrl | The url to redirect a customer after a successful checkout. | ✅ |
cancelUrl | The url to redirect a customer if they cancel the checkout. | ✅ |
granteeId | The 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. | ✅ |
owner | The ID of the customer's organisation. | ✅ |
currency | The shortname of the currency to be used in the checkout. Default - plan's product default currency. | ❌ |
quantity | The 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.
If you'd like to receive payment for a subscription, create a checkout link.
- Node SDK
- Fetch
- cURL
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',
});
const response = await fetch("https://api.salable.app/subscriptions", {
method: "POST",
headers: {
"x-api-key": "your-salable-api-key",
version: "v2"
},
body: JSON.stringify({
planUuid: "a-plan-uuid",
granteeId: "id-of-grantee",
owner: "id-of-the-grantees-organisation"
});
})
const subscription = await response.json();
curl
-XPOST
-H 'x-api-key: your-salable-api-key'
-H 'version: v2'
-d '{ "planUuid": "a-plan-uuid", "granteeId": "id-of-grantee", "owner": "id-of-the-grantees-organisation" }'
'https://api.salable.app/subscriptions'
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.
- JS SDK
- Node SDK
- Fetch
- cURL
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');
import { Salable } from '@salable/node-sdk';
const salable = new Salable('your-salable-api-key', 'v2');
const { capabilities } = await salable.licenses.check({
productUuid: 'your-product-uuid',
granteeIds: ['your-grantees-id'],
});
// Check for a capability
const isGranteeLicensedToPerformAction = capabilities.find((c) => c.capability === 'your-capability-name');
// or a feature
const isGranteeLicensedToPerformAction = capabilities.find((c) => c.capability === 'feature-name');
// or a plan
const isGranteeLicensedToPerformAction = capabilities.find((c) => c.capability === 'plan-name');
const params = new URLSearchParams();
params.append("granteeIds", "id-of-grantee");
params.append("productUuid", "your-product-uuid");
const response = await fetch(`https://api.salable.app/licenses/check?${params}`, {
headers: {
"x-api-key": "your-salable-api-key",
version: "v2"
},
})
const check = response.status === 204 ? null : await response.json();
curl
-XGET
-H 'x-api-key: your_salable_api_key'
-H 'version: v2'
'https://api.salable.app/licenses/check?productUuid=your_product_uuid&granteeIds=your-grantees-id&grace=3'
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.
- Node SDK
- Fetch
- cURL
import { Salable } from '@salable/node-sdk';
const salable = new Salable('your-salable-api-key', 'v2');
const seats = await salable.subscription.getSeats('your-subscription-uuid');
const response = await fetch(
'https://api.salable.app/subscriptions/your-subscription-uuid/seats',
{
headers: {
version: 'v2',
'x-api-key': 'your-salable-api-key',
},
}
);
const seats = await response.json();
curl
-XGET
-H 'x-api-key: your-salable-api-key'
-H 'version: v2'
'https://api.salable.app/subscriptions/your-subscription-uuid/seats'
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.
- Node SDK
- Fetch
- cURL
import { Salable } from '@salable/node-sdk';
const salable = new Salable('your-salable-api-key', 'v2');
const count = await api.subscriptions.getSeatCount('your-subscription-uuid');
const response = await fetch(
'https://api.salable.app/subscriptions/your-subscription-uuid/seats/count',
{
headers: {
version: 'v2',
'x-api-key': 'your-salable-api-key',
},
}
);
const count = await response.json();
curl
-XGET
-H 'x-api-key: your-salable-api-key'
-H 'version: v2'
'https://api.salable.app/subscriptions/your-subscription-uuid/seats/count'
Add seats
All seats created are unassigned by default. You can assign seats after they have been added to the subscription.
- Node SDK
- Fetch
- cURL
import { Salable } from '@salable/node-sdk';
const salable = new Salable('your-salable-api-key', 'v2');
await salable.subscriptions.addSeats('your-subscription-uuid', {
increment: 2,
});
await fetch("https://api.salable.app/subscriptions/your-subscription-uuid", {
method: "POST",
headers: {
"x-api-key": "your-salable-api-key",
version: "v2"
},
body: JSON.stringify({
increment: 2
});
})
curl
-XPOST
-H 'x-api-key: your-salable-api-key'
-H 'version: v2'
-d '{ "increment": 2 }'
'https://api.salable.app/subscriptions/your-subscription-uuid/seats'
Remove seats
Only unassigned seats can be removed.
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.
- Node SDK
- Fetch
- cURL
import { Salable } from '@salable/node-sdk';
const salable = new Salable('your-salable-api-key', 'v2');
await salable.subscriptions.removeSeats('your-subscription-uuid', {
decrement: 2,
});
await fetch("https://api.salable.app/subscriptions/your-subscription-uuid", {
method: "PUT",
headers: {
"x-api-key": "your-salable-api-key",
version: "v2"
},
body: JSON.stringify({
decrement: 2
});
})
curl
-XPUT
-H 'x-api-key: your-salable-api-key'
-H 'version: v2'
-d '{ "decrement": 2 }'
'https://api.salable.app/subscriptions/your-subscription-uuid/seats'
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.
- Node SDK
- Fetch
- cURL
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.
]);
await fetch("https://api.salable.app/subscriptions/your-subscription-uuid/manage-seats", {
method: "PUT",
headers: {
"x-api-key": "your-salable-api-key",
version: "v2"
},
body: JSON.stringify([
{
type: "assign",
granteeId: "your-new-grantee-id"
},
// You can perform multiple actions by passing in multiple objects.
]);
})
curl
-XPUT
-H 'x-api-key: your-salable-api-key'
-H 'version: v2'
-d '[{ "type": "assign", "granteeId": "your-new-grantee-id" }]'
'https://api.salable.app/subscriptions/your-subscription-uuid/seats'
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.
- Node SDK
- Fetch
- cURL
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.
]);
await fetch("https://api.salable.app/subscriptions/your-subscription-uuid/manage-seats", {
method: "PUT",
headers: {
"x-api-key": "your-salable-api-key",
version: "v2"
},
body: JSON.stringify([
{
type: "unassign",
granteeId: "grantee-id-to-be-unassigned"
},
// You can perform multiple actions by passing in multiple objects.
]);
})
curl
-XPUT
-H 'x-api-key: your-salable-api-key'
-H 'version: v2'
-d '[{ "type": "unassign", "granteeId": "grantee-id-to-be-unassigned" }]'
'https://api.salable.app/subscriptions/your-subscription-uuid/seats'
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.
- Node SDK
- Fetch
- cURL
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.
]);
await fetch("https://api.salable.app/subscriptions/your-subscription-uuid/manage-seats", {
method: "PUT",
headers: {
"x-api-key": "your-salable-api-key",
version: "v2"
},
body: JSON.stringify([
{
type: "replace",
granteeId: "grantee-id-to-be-replaced",
newGranteeId: "new-grantee-id"
},
// You can perform multiple actions by passing in multiple objects.
]);
})
curl
-XPUT
-H 'x-api-key: your-salable-api-key'
-H 'version: v2'
-d '[{ "type": "replace", "granteeId": "grantee-id-to-be-replaced", "newGranteeId": "new-grantee-id" }]'
'https://api.salable.app/subscriptions/your-subscription-uuid/seats'
- Node SDK
- Fetch
- cURL
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"
}
]);
await fetch("https://api.salable.app/subscriptions/your-subscription-uuid/manage-seats", {
method: "PUT",
headers: {
"x-api-key": "your-salable-api-key",
version: "v2"
},
body: JSON.stringify([
{
type: "replace",
granteeId: "current-grantee-id",
newGranteeId: "new-grantee-id"
}
]);
})
curl
-XPUT
-H 'x-api-key: your-salable-api-key'
-H 'version: v2'
-d '[{ "type": "replace", "granteeId": "current-grantee-id", "newGranteeId": "new-grantee-id" }]'
'https://api.salable.app/subscriptions/your-subscription-uuid/seats'
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.
- Node SDK
- Fetch
- cURL
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
}
);
await fetch("https://api.salable.app/subscriptions/your-subscription-uuid/change-plan", {
method: "PUT",
headers: {
"x-api-key": "your-salable-api-key",
version: "v2"
},
body: JSON.stringify({
planUuid: "the-new-plan-uuid",
});
})
curl
-XPUT
-H 'x-api-key: your-salable-api-key'
-H 'version: v2'
-d '{ "planUuid": "the-new-plan-uuid" }'
'https://api.salable.app/subscriptions/{subscriptionUuid}/change-plan'
Proration options are only applicable on subscriptions that have taken a payment.
Value | Description |
---|---|
create_prorations | Keeps 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_invoice | Immediately reflects the cost change with an invoice. |
none | Disables proration behaviour |
Cancel subscription
You can cancel a subscription with its associated subscriptionUuid
. All the subscription's associated seats will also
be canceled.
- Node SDK
- Fetch
- cURL
import { Salable } from '@salable/node-sdk';
const salable = new Salable('your-salable-api-key', 'v2');
await salable.subscriptions.cancel('your-subscription-uuid', { when: 'end' });
const params = new URLSearchParams();
params.append("when", "now");
await fetch(`https://api.salable.app/subscriptions/your-subscription-uuid/cancel?${params}`, {
method: "PUT",
})
curl
-XPUT
-H 'x-api-key: your-salable-api-key'
-H 'version: v2'
'https://api.salable.app/subscriptions/your-subscription-uuid/cancel?when=end'
The when
query parameter represents when you want the subscription to cancel.
When | Description |
---|---|
now | Immediately cancels the Subscription. If the Subscription is paid, the customer will be immediately invoiced. |
end | Cancels 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. |