Overview
Learn about the billing package.
The starter kits comes with a billing package that enables you to charge your users, display relevant information and let them manage their plan or billing info.
Monetization
The billing package supports multiple monetization options:
-
Subscriptions: Automatically generates recurring invoices at fixed intervals, typically monthly or annually. Ideal for products that offer ongoing access.
-
One-time Payments: Charges the customer a single upfront payment for perpetual access. Useful for lifetime deals, downloadable products or purchasable addons.
-
Metered Usage: Invoices customers based on measured usage over a billing period, commonly monthly. This is similar to utility billing (e.g. your electricity bill).
The monetization options are not mutually exclusive. You can mix and combine them.
Example: You can charge $9 a month (subscription) with 1000 free requests per month and $0.01 for each request above that (meter usage) in the same subscription billing cycle and generate one invoice with two line items.
Configuration
The billing configuration ensures consistent behavior across the application and any billing provider.
Let's say we want to add a "Pro plan" that
- is recommended
- has 7 days trials
- costs $24/month or $199/year
export const billingConfig = createBillingConfig({ products: [ { id: 'pro', name: 'Pro', description: 'Best for most teams.', label: 'Get started', recommended: true, features: ['Feature 1', 'Feature 2'], plans: [ { id: 'plan-pro-month', displayIntervals: [PriceInterval.Month], trialDays: 7, prices: [ { id: 'price-pro-month-id', interval: PriceInterval.Month, type: PriceType.Recurring, model: PriceModel.Flat, cost: 24, currency: 'USD' } ] }, { id: 'plan-pro-year', displayIntervals: [PriceInterval.Year], trialDays: 7, prices: [ { id: 'price-pro-year-id', interval: PriceInterval.Year, type: PriceType.Recurring, model: PriceModel.Flat, cost: 199, currency: 'USD' } ] } ] } ]});You can add multiple products including free, enterprise or undefined deals. Instead of a flat billing model you can also bill per_seat or metered.
Purchases
The product id is used to identify a product. It is defined in the key property of the product object from the config file like free, pro, enterprise or undefined.
Client-side
You can check if a user has a purchased product by using the usePurchases hook.
The usePurchases hook returns the following properties:
purchasedProducts: An array of all the active purchases of the user.hasPurchasedProduct: A function to check if the user has an active product. Optionally takes a plan id or an array of plan ids as argument to check for specific plans.
function MyComponent() { const { purchasedProducts, hasPurchasedProduct } = usePurchases(); const isPayingUser = hasPurchasedProduct(); // more specific const hasProPurchase = hasPurchasedProduct('pro'); const hasProOrEnterprisePurchase = hasPurchasedProduct(['pro', 'enterprise']); const hasLifetimeAccess = hasPurchasedProduct('lifetime'); // or alternatively const hasProPurchase = purchasedProducts.includes('pro');}Server-side
You can also check for purchases on the server-side by utilizing the createPurchasesHelper function.
import { getAuthOrganizationContext } from '@workspace/auth/context';import { createPurchasesHelper } from '@workspace/billing/helpers';const ctx = await getAuthOrganizationContext();const { purchasedProducts, hasPurchasedProduct } = createPurchasesHelper( ctx.organization);Webhooks
Webhooks are used to receive events from the billing provider. They are important to get the latest data so your application is in sync with your billing provider.
Synchronization
If you plan to migrate an existing system or want to ensure on a daily/weekly/monthly-basis that you have up-to-date data on demand, you can use the synchronization method. This will sync all relevant data between your database and the billing provider. We added experimental support for that.