For the complete documentation index, see llms.txt. Prefer markdown by appending .md to documentation URLs or sending Accept: text/markdown.

Billing

Extension billing flows through your web app checkout. Gate premium extension features using the same subscriptions and entitlements.

Billing for the browser extension is intentionally handled through the web app, not inside the extension UI itself.

That means the usual flow is:

  1. a user upgrades or purchases a plan in the web app
  2. TurboStarter syncs that billing data through the shared billing system
  3. the extension reads the current billing summary and unlocks features accordingly

This keeps checkout, billing portals, invoices, and provider-specific flows in the web app, while the extension only needs to react to the user's current billing state.

Extension capabilities

The extension does not create checkout sessions or host pricing tables. Instead, it reads billing state from the shared API and uses that data to:

  • show the current plan
  • gate premium features — see the extension feature-based access recipe
  • decide whether a user or organization has access
  • link users back to the web dashboard when they need to upgrade

If your app supports organizations, billing in the extension can also be organization-aware.

Fetching customer data

When your user has purchased a plan from your landing page or web app, you can easily fetch their data using the API.

To do so, just invoke the summary query on the billing router to get the summary of the user's billing data:

customer-screen.tsx
import { getActivePlan } from "@workspace/billing";

import { api } from "~/lib/api";

export default function CustomerScreen() {
  const summary = useQuery({
    queryKey: ["summary"],
    queryFn: handle(api.billing.summary.$get),
  });

  if (summary.isLoading) {
    return <p>Loading...</p>;
  }

  const plan = getActivePlan(summary.data);

  return <p>{plan}</p>;
}

You may also want to ensure that user is logged in before fetching their billing data to avoid unnecessary API calls.

header.tsx
import { api } from "~/lib/api";
import { authClient } from "~/lib/auth";

export const User = () => {
  const session = authClient.useSession();

  const summary = useQuery({
    queryKey: ["summary"],
    queryFn: handle(api.billing.summary.$get),
    enabled: !!session.data?.user, 
  });

  if (!session.data?.user || !summary.data) {
    return null;
  }

  return (
    <div>
      <p>{session.data.user.email}</p>
      <p>{summary.data.length}</p>
    </div>
  );
};

Read more about auth in extension.

Use the right billing reference

If your extension supports both personal and organization workflows, make sure you fetch billing summary for the correct referenceId. The active organization should usually take precedence over the personal account.

For step-by-step gating patterns, upgrade links, and API enforcement, follow the feature-based access recipe.

How is this guide?

Last updated on

On this page

Ship your startup everywhere. In minutes.Try TurboStarter