Developer SDK

One npm install. Full SaaS backend.

React hooks for the frontend. Server functions for the backend. Auth, billing, credits, quotas, workspaces, permissions, notifications, and 13 pre-built settings screens. TypeScript-first with full type safety.

$ npm install @buildbase/sdk

Three entry points, one package

Import what you need. React SDK for the frontend, server SDK for the backend, data module for reference data.

React SDK

/react

40+ hooks, 20+ conditional components, 13 pre-built settings screens. Add a provider, call hooks, ship. Works with Next.js, Vite, Remix, or any React setup.

  • useSaaSAuth() — sign in, sign out, session
  • useSaaSWorkspaces() — CRUD, members, roles
  • useSubscription() — plans, checkout, trials
  • useCreditBalance() — consume, purchase, track
  • useQuotaUsageStatus() — record, enforce limits
  • usePermissions() — 3-tier permission gates
  • useTrialStatus() — days remaining, ending?
  • useSeatStatus() — seat limits, invite checks
  • useTranslation() — i18n, RTL, native numerals
  • usePushNotifications() — subscribe, permission

Server SDK

@buildbase/sdk

Framework-agnostic. Works with Next.js API routes, Express, Hono, Fastify, or any Node.js backend. Factory pattern with automatic session resolution.

  • bb.usage.record() — metered billing
  • bb.usage.recordBatch() — bulk (up to 100)
  • bb.credits.consume() — with idempotency
  • bb.subscription.get() — check plan status
  • bb.subscription.checkout() — Stripe session
  • bb.workspace.list/create/update/delete()
  • bb.users.invite() — add workspace member
  • bb.notification.send() — email + push
  • bb.permissions.check() — verify access
  • bb.withSession() — background jobs

Shared

/data + core exports

Reference data, billing utilities, permission constants, and150+ TypeScript types shared across frontend and backend. Zero React dependency.

  • countries, currencies, languages, timezones
  • formatCents() — locale-aware currency
  • getPricingVariant() — multi-currency plans
  • calculateTotalSubscriptionCents()
  • validateInvite() — seat limit checks
  • Permission.* — 12 platform permissions
  • resolvePermissions() — 3-tier resolution
  • verifyWebhookSignature() — HMAC-SHA256
  • parseWebhookEvent() — typed payloads
  • eventEmitter — cross-component events

Production code, not pseudocode

Every example runs as-is. Copy, paste, ship.

Setup

Add the provider

Add the provider to the root layout. Pass the org ID and auth config. The SDK handles session management, token refresh, workspace loading, and settings resolution automatically.

app/providers.tsxTSX
import { ApiVersion } from '@buildbase/sdk';
import { SaaSOSProvider } from '@buildbase/sdk/react';

export default function Providers({ children }) {
  return (
    <SaaSOSProvider
      serverUrl="https://api.yourapp.com"
      version={ApiVersion.V1}
      orgId="your-org-id"
      auth={{
        clientId: 'your-client-id',
        redirectUrl: 'http://localhost:3000',
      }}
      locale="en" // en, es, fr, de, ja, zh, hi, ar
    >
      {children}
    </SaaSOSProvider>
  );
}
Authentication

Sign in, sign out

One hook returns the user, auth status, sign in, sign out, and openWorkspaceSettings() to open any settings screen. Conditional components render based on auth state.

components/app.tsxTSX
import {
  useSaaSAuth,
  WhenAuthenticated,
  WhenUnauthenticated,
} from '@buildbase/sdk/react';

function App() {
  const { user, signIn, signOut, openWorkspaceSettings } = useSaaSAuth();

  return (
    <>
      <WhenUnauthenticated>
        <button onClick={() => signIn()}>Sign In</button>
      </WhenUnauthenticated>

      <WhenAuthenticated>
        <p>Welcome, {user?.name}</p>
        <button onClick={() => openWorkspaceSettings('subscription')}>
          Manage Plan
        </button>
        <button onClick={signOut}>Sign Out</button>
      </WhenAuthenticated>
    </>
  );
}
Subscriptions & Trials

Paywalls as components

useTrialStatus() returns days remaining and whether the trial is ending. Conditional components gate UI by subscription state, specific plans, or trial status. Checkout creates a Stripe session automatically.

pages/billing.tsxTSX
import {
  useSubscription,
  useTrialStatus,
  useCreateCheckoutSession,
  WhenTrialEnding,
  WhenNoSubscription,
  WhenSubscriptionToPlans,
} from '@buildbase/sdk/react';

function BillingPage({ workspaceId }) {
  const { subscription } = useSubscription(workspaceId);
  const { isTrialing, daysRemaining } = useTrialStatus();
  const { createCheckoutSession } = useCreateCheckoutSession(workspaceId);

  return (
    <>
      <WhenTrialEnding daysThreshold={3}>
        <Banner>{daysRemaining} days left in your trial.</Banner>
      </WhenTrialEnding>

      <WhenNoSubscription>
        <button onClick={() => createCheckoutSession({
          planVersionId: 'pro-v1',
          billingInterval: 'monthly',
        })}>
          Subscribe to Pro
        </button>
      </WhenNoSubscription>

      <WhenSubscriptionToPlans plans={['starter']}>
        <UpgradePrompt />
      </WhenSubscriptionToPlans>
    </>
  );
}
Credits & Expiration

Consume, track, gate

Consume credits with idempotency keys for safe retries. Returns a typed INSUFFICIENT_CREDITS error on 402 with available and requested fields. Track expiring credits with a configurable lookahead window (1-90 days).

components/ai-feature.tsxTSX
import {
  useCreditBalance,
  useConsumeCredits,
  useExpiringCredits,
  WhenCreditsExhausted,
  WhenCreditsLow,
} from '@buildbase/sdk/react';

function AIFeature({ workspaceId }) {
  const { balance } = useCreditBalance(workspaceId);
  const { consumeCredits } = useConsumeCredits(workspaceId);
  const { expiringCredits } = useExpiringCredits(workspaceId, 7);

  const handleGenerate = async () => {
    try {
      await consumeCredits({ amount: 10, description: 'AI generation' });
      // proceed with generation
    } catch (err) {
      if (err.code === 'INSUFFICIENT_CREDITS') {
        // err.available and err.requested are available
      }
    }
  };

  return (
    <>
      <p>Credits: {balance?.available}</p>
      {expiringCredits > 0 && <p>{expiringCredits} credits expire soon</p>}

      <WhenCreditsLow threshold={10}>
        <p>Running low — buy more credits.</p>
      </WhenCreditsLow>

      <WhenCreditsExhausted>
        <p>No credits left.</p>
      </WhenCreditsExhausted>

      <button onClick={handleGenerate}>Generate (10 credits)</button>
    </>
  );
}
Server-Side

Backend integration

The BuildBase() factory resolves sessions automatically from a callback. For background jobs or non-request contexts, use withSession() to create a scoped client. Supports configurable timeout, retry with exponential backoff, and debug logging.

app/api/generate/route.tsTSX
import BuildBase from '@buildbase/sdk';

const bb = BuildBase({
  serverUrl: 'https://api.yourapp.com',
  orgId: 'your-org-id',
  getSessionId: async () => {
    const cookies = await getCookies();
    return cookies.get('bb-session')?.value ?? null;
  },
});

// API route — record usage and enforce quota
export async function POST(req) {
  const usage = await bb.usage.record(workspaceId, {
    quotaSlug: 'api-calls',
    quantity: 1,
    idempotencyKey: req.headers.get('x-request-id'),
  });

  if (usage.available <= 0) {
    return Response.json({ error: 'Quota exceeded' }, { status: 429 });
  }

  return Response.json({ remaining: usage.available });
}

// Background job — use withSession() for non-request contexts
const api = bb.withSession(serviceAccountSessionId);
await api.credits.consume(workspaceId, { amount: 50 });
await api.notification.send(workspaceId, 'job-completed');
Webhooks

Verify and handle

HMAC-SHA256 signature verification with timing-safe comparison and configurable max age (default 5 minutes). Parse events into typed payloads. Handle subscription changes, credit events, workspace actions, and more.

app/api/webhooks/route.tsTSX
import { parseWebhookEvent } from '@buildbase/sdk';

export async function POST(req) {
  const body = await req.text();

  // Verifies the signature and parses the payload — returns null on failure
  const parsed = parseWebhookEvent({
    body,
    signature: req.headers.get('x-buildbase-signature'),
    timestamp: req.headers.get('x-buildbase-timestamp'),
    secret: process.env.WEBHOOK_SECRET,
  });

  if (!parsed) {
    return Response.json({ error: 'Invalid signature' }, { status: 401 });
  }

  switch (parsed.event) {
    case 'subscription.upgraded':
      await enablePremiumFeatures(parsed.data.workspaceId);
      break;
    case 'credit.low_balance':
      await notifyTeam(parsed.data.workspaceId);
      break;
    case 'workspace.member_added':
      await syncToExternalCRM(parsed.data);
      break;
  }

  return Response.json({ received: true });
}
Permissions & Seats

3-tier permission resolution

Permissions resolve through three layers: workspace overrides, then org settings, then SDK defaults. Owners get all permissions automatically. useSeatStatus() returns member count, included seats, billable seats, max-seat status, and an invite validation result with a human-readable block reason.

pages/team.tsxTSX
import {
  usePermissions,
  useSaaSAuth,
  useSeatStatus,
  WhenPermission,
  WhenWorkspaceRoles,
  Permission,
} from '@buildbase/sdk/react';

function TeamPage({ workspace }) {
  const { can } = usePermissions();
  const { openWorkspaceSettings } = useSaaSAuth();
  const {
    memberCount, includedSeats, availableSeats,
    isAtMax, canInvite, inviteBlockReason,
  } = useSeatStatus(workspace);

  return (
    <>
      <p>{memberCount} of {includedSeats} seats used</p>

      <WhenPermission permission={Permission.WORKSPACE_MEMBERS_INVITE}>
        <button disabled={!canInvite}>
          {canInvite ? 'Invite Member' : inviteBlockReason}
        </button>
      </WhenPermission>

      <WhenWorkspaceRoles roles={['owner', 'admin']}>
        <button onClick={() => openWorkspaceSettings('permissions')}>
          Manage Permissions
        </button>
      </WhenWorkspaceRoles>

      {can(Permission.WORKSPACE_BILLING_MANAGE) && <BillingLink />}
    </>
  );
}
Internationalization

8 languages, native numerals

600+ translated strings across all settings screens. ICU MessageFormat for pluralization. Native numeral systems: Devanagari for Hindi, Arabic-Indic for Arabic. RTL layout direction for Arabic. English bundled by default; other languages lazy-loaded.

components/price.tsxTSX
import { useTranslation, SUPPORTED_LOCALES } from '@buildbase/sdk/react';
// Locales: 'en', 'es', 'fr', 'de', 'ja', 'zh', 'hi', 'ar'

function PriceDisplay({ cents, currency }) {
  const { t, fmtCents, fmtNum, dir } = useTranslation();

  return (
    <div dir={dir}> {/* Automatically 'rtl' for Arabic */}
      <p>{t('subscription.currentPlan')}</p>
      <p>{fmtCents(cents, currency)}</p>
      {/* $49.99 (en) | ४९.९९ (hi, Devanagari) | ٤٩٫٩٩ (ar, Arabic-Indic) */}
      <p>{fmtNum(1234)}</p>
      {/* 1,234 (en) | १,२३४ (hi) | ١٬٢٣٤ (ar) */}
    </div>
  );
}

13 pre-built settings screens

Every SaaS needs workspace settings. The SDK ships a production-ready settings dialog opened with one function call. Translated, permission-gated, and responsive.

openWorkspaceSettings('subscription')
Profile

Edit name, email, language, country, currency, and timezone

Security

Manage passkeys and review or sign out active sessions

Devices

Review signed-in devices, rename them, sign out, or forget unrecognized ones

Connected Agents

Review AI agents with account access and disconnect them to revoke access

General

Set workspace name, icon, and billing currency

Members

Invite members by email, assign roles, track seat usage, remove access

Subscription

View current plan, switch plans, cancel or resume, access invoices

Usage

Track per-quota usage, overage costs, and billing cycle

Credits

Check balance, purchase packages, review transaction history

Features

Enable or disable feature flags per workspace

Notifications

Subscribe to push notifications, toggle per-event email and push delivery

Permissions

Edit role-permission matrix with granular toggle controls

Danger Zone

Permanently delete workspace with confirmation

Also included: <PricingPage>, <CreditStorePage>, <WorkspaceSwitcher>, and <BetaForm> — all with render props for full layout control.

Declarative UI gating

No if-statements for permissions, subscriptions, or feature flags. Wrap UI in conditional components. The SDK resolves state and renders or hides children.

Auth

<WhenAuthenticated>
<WhenUnauthenticated>

Subscriptions

<WhenSubscription>
<WhenNoSubscription>
<WhenSubscriptionToPlans plans={[]}>
<WhenTrialing>
<WhenNotTrialing>
<WhenTrialEnding daysThreshold={3}>

Quotas

<WhenQuotaAvailable slug="">
<WhenQuotaExhausted slug="">
<WhenQuotaOverage slug="">
<WhenQuotaThreshold slug="" threshold={80}>

Credits

<WhenCreditsAvailable min={1}>
<WhenCreditsExhausted>
<WhenCreditsLow threshold={10}>

Permissions & Roles

<WhenPermission permission="">
<WhenRoles roles={[]}>
<WhenWorkspaceRoles roles={[]}>

Feature Flags

<WhenWorkspaceFeatureEnabled slug="">
<WhenWorkspaceFeatureDisabled slug="">
<WhenUserFeatureEnabled slug="">
<WhenUserFeatureDisabled slug="">

Also included

8 languages built in

English, Spanish, French, German, Japanese, Chinese, Hindi, Arabic. ICU MessageFormat with pluralization. RTL for Arabic. Lazy-loaded — only English in the initial bundle.

Multi-currency billing

Per-plan pricing variants by currency. formatCents() for locale-aware display. Workspace billing currency lock. Available currencies auto-detected from plan config.

Notifications

Send email and push notifications from the server SDK. Per-event user preferences with toggles. Browser push with VAPID auto-setup. Browser-specific unblock instructions.

Seat-based pricing

useSeatStatus() calculates included seats, billable extras, per-seat cost, invite eligibility, and human-readable block reasons. Syncs with subscription state.

Pricing utilities

calculateTotalSubscriptionCents(), getBasePriceCents(), getQuotaOverageCents(), getBillingIntervalAndCurrencyFromPriceId() — full pricing math without Stripe SDK.

Usage batch recording

bb.usage.recordBatch() sends up to 100 usage events in one call. Idempotency keys per item. Returns per-item success/failure results.

Event system

Global eventEmitter for cross-component communication. Workspace CRUD, user changes, and role updates emit typed events components can subscribe to.

Auth intent preservation

saveAuthIntent() stores the destination before auth redirect. consumeAuthIntent() restores it after sign-in. Survives full page reloads.

40+

React Hooks

20+

Conditional Components

13

Settings Screens

150+

TypeScript Types

8

Languages

Get started

Install the SDK, add the provider, start shipping. Auth, billing, workspaces, permissions, and settings screens are handled.

Simple pricingCancel anytimeFull platform access