Usage-based billing
With the usage-based model, you charge your customers based on how much they use your product during a billing cycle. The customer's usage on the plan is monitored, and they are billed the total amount at the end of their billing cycle.
Taking payments
To receive payment for usage, you'll need to create a Stripe checkout with your salable usage plan. Here, a customer can add their bank card details but will not be charged anything at this point. At the end of each billing cycle their consumption will be totaled and invoiced. A customer will only pay for the consumption they use, if they don't consume anything in a cycle, they won't be charged anything but still invoiced for a total of 0 in the subscription's currency.
- JS SDK
- Node SDK
- Fetch
- cURL
import { getCheckoutLink } from '@salable/js'
const { checkoutUrl } = await getCheckoutLink({
apiKey: 'your-salable-api-key',
planUuid: 'your-salable-usage-plan-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-salable-usage-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-salable-usage-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-salable-usage-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. | ❌ |
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-salable-usage-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: "your-salable-usage-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": "your-salable-usage-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'
Update seat
Change who can access the subscription.
- 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'
Usage Records
The consumption on a usage subscription is stored in usage records, a record is created per cycle. This allows you to see the entire usage history of the subscription as well as the current cycles consumption. A record will have a status, the table below explains what each one means.
Status | Description |
---|---|
current | Indicates the usage record for the current cycle of the subscription. Here, you can find how much usage a customer has consumed in the current cycle. |
recorded | When a subscription's cycle has finished, the current usage record is finalised and set as recorded . The usage record cannot be updated once it has been recorded. |
final | The usage record that was current at the time the subscription was cancelled. |
Get all usage records
This endpoint uses cursor pagination.
- Node SDK
- Fetch
- cURL
import { Salable } from '@salable/node-sdk';
const salable = new Salable('your-salable-api-key', 'v2');
const usage = await salable.usage.getAllUsageRecords({
granteeId: 'id-of-grantee',
});
const params = new URLSearchParams();
params.append("granteeId", "id-of-grantee");
const response = await fetch(`https://api.salable.app/usage?${params}`, {
headers: {
"x-api-key": "your-salable-api-key",
version: "v2"
},
})
const usage = await response.json();
curl
-XGET
-H 'x-api-key: your_salable_api_key'
-H 'version: v2'
'https://api.salable.app/usage?granteeId=your-grantees-id'
Get current usage
Retrieve the current usage for a grantee on a specific plan.
- Node SDK
- Fetch
- cURL
import { Salable } from '@salable/node-sdk';
const salable = new Salable('your-salable-api-key', 'v2');
const currentUsage = await api.usage.getCurrentUsageRecord({
granteeId: 'grantee-id',
planUuid: 'usage-plan-uuid'
});
const response = await fetch(
'https://api.salable.app/usage/current?granteeId=grantee-id&planUuid=usage-plan-uuid',
{
headers: {
version: 'v2',
'x-api-key': 'your-salable-api-key',
},
}
);
const currentUsage = await response.json();
curl
-XGET
-H 'x-api-key: your-salable-api-key'
-H 'version: v2'
'https://api.salable.app/usage/current?granteeId=grantee-id&planUuid=usage-plan-uuid'
Update usage
Increment consumption on a usage subscription.
- Node SDK
- Fetch
- cURL
import { Salable } from '@salable/node-sdk';
const salable = new Salable('your-salable-api-key', 'v2');
const records = await salable.usage.updateLicenseUsage({
granteeId: 'grantee-id',
planUuid: 'usage-plan-uuid',
increment: 1,
idempotencyKey: 'unique-key-for-request'
});
await fetch(
'https://api.salable.app/usage?granteeId=grantee-id&planUuid=usage-plan-uuid',
{
method: 'PUT',
headers: {
version: 'v2',
'x-api-key': 'your-salable-api-key',
'unique-key': 'unique-key-for-request'
},
body: JSON.stringify({
granteeId: 'grantee-id',
planUuid: 'usage-plan-uuid',
increment: 1,
})
}
);
curl
-XPUT
-H 'x-api-key: your-salable-api-key'
-H 'version: v2'
-H 'unique-key: unique-key-for-request'
-d '{ "granteeId": "grantee-id", "planUuid": "usage-plan-uuid", "increment": 1 }'
'https://api.salable.app/usage'
Upgrade and downgrade
Useful if you need to update the plan your grantee is on. For example, if they have upgraded or downgraded you would want to update the subscription to reflect this. If the subscription is paid, all consumption in the current billing cycle will be finalised and invoiced before moving the customer to the new plan.
- 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' }
);
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 not available on usage subscriptions.
Cancel subscription
You can cancel a subscription with its associated subscriptionUuid
. If the subscription is paid, at the time of the
subscription being canceled all consumption in the current billing cycle will be finalised and invoiced.
- 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. |
Demos
Usage-based billing in Next.js
Miro app with usage-based billing