Overview
Add consumption-based billing with credit packages, balance tracking, and usage limits.
BuildBase provides a credit system for consumption-based billing. Use CreditStorePage to sell credit packages, useCreditBalance to show the balance, and useConsumeCredits to deduct credits when users perform actions.
import { useConsumeCredits, useCreditBalance } from '@buildbase/sdk/react';
function AIGenerator({ workspaceId }) {
const { balance } = useCreditBalance(workspaceId);
const { consumeCredits } = useConsumeCredits(workspaceId);
const handleGenerate = async () => {
try {
await consumeCredits({ amount: 10, description: 'AI generation' });
} catch (err) {
if (err.code === 'INSUFFICIENT_CREDITS') {
alert(`Need 10 credits, only ${err.available} available`);
}
}
};
return (
<div>
<p>{balance?.available} credits remaining</p>
<button onClick={handleGenerate}>Generate (10 credits)</button>
</div>
);
}Before you start
Create credit packages in the BuildBase dashboard first.
openCreditStore()
Opens the credit purchase UI from anywhere in your app — ideal for "Buy Credits" buttons or insufficient-credits error handlers:
import { useSaaSAuth } from '@buildbase/sdk/react';
function BuyCreditsButton() {
const { openCreditStore } = useSaaSAuth();
return <button onClick={() => openCreditStore()}>Buy Credits</button>;
}CreditStorePage
For a dedicated credits page, use the headless CreditStorePage component. It fetches credit packages and handles purchase logic; you render the UI through the required children render prop:
import { CreditStorePage } from '@buildbase/sdk/react';
function BuyCredits() {
return (
<CreditStorePage>
{({ loading, error, packages, selectPackage }) => {
if (loading) return <p>Loading packages...</p>;
if (error) return <p>{error}</p>;
return (
<div className="grid grid-cols-3 gap-4">
{packages.map((pkg) => (
<button key={pkg._id} onClick={() => selectPackage(pkg._id)}>
Buy {pkg.creditAmount} credits — {pkg.name}
</button>
))}
</div>
);
}}
</CreditStorePage>
);
}selectPackage(packageId) opens the workspace settings Credits tab for authenticated users, or triggers sign-in first (set redirectBaseUrl on CreditStorePage for the unauthenticated flow). The render prop also receives refetch() and an optional notes string from the API.
Conditional components
Show different UI based on the credit balance:
import {
WhenCreditsAvailable,
WhenCreditsExhausted,
WhenCreditsLow,
} from '@buildbase/sdk/react';
function CreditGate({ children }) {
return (
<>
<WhenCreditsExhausted>
<p>
No credits. <a href="/credits">Buy more</a>
</p>
</WhenCreditsExhausted>
<WhenCreditsLow threshold={10}>
<p>Running low on credits.</p>
</WhenCreditsLow>
<WhenCreditsAvailable min={1}>{children}</WhenCreditsAvailable>
</>
);
}| Component | Renders when |
|---|---|
WhenCreditsAvailable | Balance at or above min (default 1) |
WhenCreditsExhausted | Balance is 0 |
WhenCreditsLow | Balance at or below threshold |
Hooks
| Hook | What it returns |
|---|---|
useCreditBalance(workspaceId) | balance.available, balance.totalGranted, balance.totalConsumed |
useConsumeCredits(workspaceId) | consumeCredits({ amount, description, idempotencyKey }) |
useExpiringCredits(workspaceId, days) | Credits expiring within N days |
usePurchaseCredits(workspaceId) | Start Stripe Checkout for credit packages |
useCreditTransactions(workspaceId) | Transaction history |
Server-side
Consume credits from your backend for operations you control server-side:
import BuildBase from '@buildbase/sdk';
const bb = BuildBase({ serverUrl, orgId, getSessionId });
try {
await bb.credits.consume(workspaceId, {
amount: 50,
description: 'Batch export',
idempotencyKey: req.headers.get('x-request-id'),
});
} catch (err) {
if (err.code === 'INSUFFICIENT_CREDITS') {
return Response.json({ error: 'Not enough credits' }, { status: 402 });
}
}Next Steps
- Quotas — Enforce usage limits per plan.
- Feature Flags — Gate features by plan or user.