Credits & Usage Metering

Charge for usage, without building a ledger.

Workspaces buy credit packs through Stripe or get credits with their plan, and your app spends them with one call that refuses to take the balance below zero. For allowances there are quotas: a per-plan limit, followed by either overage billing or a hard stop.

Your app is an organization in BuildBase. Your users sign in and work inside workspaces - one per team or customer.

You set up

In the console and the SDK

  • Credit packs and their prices, in the console
  • Credits included with a plan, if you want them
  • One call where the paid work happens, like an AI generation

Your users get

Inside their workspace

  • A credit balance on their workspace
  • A store to buy more credits, through Stripe
  • A clear 'not enough credits' message, never a surprise bill

Usage-based pricing without the ledger work

Balances, buckets, expiry and the Stripe purchase are handled. You call consume where the work happens.

Sell Credit Packs

Set how many credits a pack holds and its price in each currency. Users buy through Stripe from a ready-made store.

Spend Safely

One call takes credits and returns the new balance. A retry never charges twice, and the balance never goes below zero.

Credits With a Plan

Include credits with a plan, once or every month, topped up or reset at renewal.

Oldest Spent First

Credits closest to expiring are used first, and users can see what is about to run out.

A Full History

Every purchase, spend, grant and refund is recorded with the balance after it. You can grant or take back credits per workspace.

Usage Limits by Plan

Give each plan an allowance, like API calls a month. Past it, you either bill the overage or stop the action.

Spend credits where the work happens

Gate the button with WhenCreditsAvailable and spend from the client, or charge from your API route and return a 402 when the balance runs out.

components/generate-button.tsxTSX
import {
  useConsumeCredits,
  useSaaSAuth,
  useSaaSWorkspaces,
  WhenCreditsAvailable,
  WhenCreditsLow,
} from '@buildbase/sdk/react';

export function GenerateButton() {
  const { currentWorkspace } = useSaaSWorkspaces();
  const { openCreditStore } = useSaaSAuth();
  const { consumeCredits, loading } = useConsumeCredits(currentWorkspace?._id);

  const generate = async () => {
    try {
      await consumeCredits({ amount: 10, description: 'AI generation' });
      // run the generation
    } catch (err: any) {
      if (err.code === 'INSUFFICIENT_CREDITS') openCreditStore();
    }
  };

  return (
    <>
      <WhenCreditsLow threshold={20}>
        <p>Running low on credits.</p>
      </WhenCreditsLow>
      <WhenCreditsAvailable
        min={10}
        fallbackComponent={<button onClick={() => openCreditStore()}>Buy credits</button>}
      >
        <button onClick={generate} disabled={loading}>
          Generate (10 credits)
        </button>
      </WhenCreditsAvailable>
    </>
  );
}
app/api/export/route.tsTSX
import BuildBase from '@buildbase/sdk';
import { cookies } from 'next/headers';

const bb = BuildBase({
  serverUrl: process.env.BUILDBASE_SERVER_URL!,
  orgId: process.env.BUILDBASE_ORG_ID!,
  getSessionId: async () =>
    (await cookies()).get('bb-session-id')?.value ?? null,
});

export async function POST(req: Request) {
  const { workspaceId } = await req.json();

  try {
    const { balanceAfter } = await bb.credits.consume(workspaceId, {
      amount: 50,
      description: 'Batch export',
      idempotencyKey: req.headers.get('x-request-id') ?? undefined,
    });
    // run the export
    return Response.json({ balanceAfter });
  } catch (err: any) {
    if (err.code === 'INSUFFICIENT_CREDITS') {
      return Response.json({ error: 'Not enough credits' }, { status: 402 });
    }
    throw err;
  }
}

Frequently Asked Questions

What people ask about Credits.

Do my users see this?

Yes. They see a credit balance on their workspace, a store to buy more, and a clear message when there are not enough credits.

What is the difference between credits and quotas?

Credits are a balance your users buy or get with a plan, and spend. Quotas are a per-plan allowance, like API calls a month, that resets every month and is either billed as overage or capped.

Can a retry charge twice?

Not if you pass the same idempotency key. The balance also never goes below zero - a short balance is refused, not overdrawn.

Do credits expire?

Purchased credits expire only when the pack has a validity period. Plan credits can also expire when they renew or when the plan changes. Credits closest to expiring are spent first.

Put a price on your most expensive action

Create a credit pack in the console, then call consumeCredits() where the work happens. Stripe handles the purchase.

7-day free trialNo credit card requiredCancel anytime