Skip to main content
Docs

Clerk billing for B2B SaaS

Clerk billing for B2B SaaS allows you to create plans and manage subscriptions for companies or organizations in your application. If you'd like to charge individual users, see Billing for B2C SaaS. You can also combine both B2C and B2B billing in the same application.

Enable billing

To enable billing for your application, navigate to the Billing Settings page in the Clerk Dashboard. This page will guide you through enabling billing for your application.

Clerk billing costs just 0.7% per transaction, plus Stripe's transaction fees which are paid directly to Stripe.

Payment gateway

Once you have enabled billing, you will see the following Payment gateway options for collecting payments via Stripe:

  • Clerk development gateway: A shared test Stripe account so developers can get started testing and building with billing in development without needing to create and configure a Stripe account.
  • Stripe account: Use your own Stripe account.

Create a plan

Subscription plans are what your customers subscribe to. There is no limit to the number of plans you can create. If your Clerk instance has existing custom permissions, the corresponding features from those permissions will automatically be added to the free plan for orgs. This ensures that organization members get the same set of custom permissions when billing is enabled, because all organizations start on the free plan.

To create a plan, navigate to the Plans page in the Clerk Dashboard. Here, you can create, edit, and delete plans. To setup B2B billing, select the Plans for Organizations tab and select Add Plan. When creating a plan, you can also create features for the plan; see the next section for more information.

Tip

What is the Publicly available option?

Add features to a plan

Features make it easy to give entitlements to your plans. You can add any number of features to a plan.

You can add a feature to a plan when you are creating a plan. To add it after a plan is created:

  1. Navigate to the Plans page in the Clerk Dashboard.
  2. Select the plan you'd like to add a feature to.
  3. In the Features section, select Add Feature.

Tip

What is the Publicly available option?

Create a pricing page

You can create a pricing page by using the <PricingTable /> component. This component displays a table of plans and features that customers can subscribe to. It's recommended to create a dedicated page, as shown in the following example.

app/pricing/page.tsx
import { PricingTable } from '@clerk/nextjs'

export default function Page() {
  return (
    <div style={{ maxWidth: '800px', margin: '0 auto', padding: '0 1rem' }}>
      <PricingTable />
    </div>
  )
}

Control access with features, plans, and permissions

You can use Clerk's features, plans, and permissions to gate access to content using authorization checks. There are a few ways to do this, but the recommended and simplest way is either using the has() method or the <Protect> component.

Permission-based authorization checks link with feature-based authorization checks. This means that if you are checking a custom permission, it will only work if the feature part of the permission key (org:<feature>:<permission>) is a feature included in the organization's active plan. For example, say you want to check if an organization member has the custom permission org:teams:manage, where teams is the feature. Before performing the authorization check, you need to ensure that the user's organization is subscribed to a plan that has the teams feature. If the user's organization is not subscribed to a plan that has the teams feature, the authorization check will always return false, even if the user has the custom permission.

The has() method is available for any JavaScript framework, while <Protect> is only available for React-based frameworks.

Example: Using has()

Use the has() method to test if the organization has access to a plan:

const { has } = await auth()
const hasPremiumAccess = has({ plan: 'gold' })

Or a feature:

const { has } = await auth()
const hasPremiumAccess = has({ feature: 'widgets' })

The has() method checks if the organization has been granted a specific type of access control (role, permission, feature, or plan) and returns a boolean value. It is available on the auth object on the server. Depending on the framework you are using, you will access the auth object differently.

Tip

Why aren't custom permissions appearing in the session token (JWT) or in API responses (including the result of the has() check)?

The following example accesses the auth object and the has() method using the Next.js-specific auth() helper.

The following example demonstrates how to use has() to check if an organization has a plan.

app/page.tsx
import { auth } from '@clerk/nextjs/server'

export default async function Page() {
  // Use `auth()` helper to access the `has()` method
  const { has } = await auth()

  // Use `has()` method to check if an organization has a Plan
  const hasBronzePlan = has({ plan: 'bronze' })

  if (!hasBronzePlan) return <h1>Only subscribers to the Bronze plan can access this content.</h1>

  return <h1>For Bronze subscribers only</h1>
}

The following example demonstrates how to use has() to check if an organization has a feature.

app/page.tsx
import { auth } from '@clerk/nextjs/server'

export default async function Page() {
  // Use `auth()` helper to access the `has()` method
  const { has } = await auth()

  // Use `has()` method to check if an organization has a Feature
  const hasPremiumAccess = has({ feature: 'premium_access' })

  if (!hasPremiumAccess)
    return <h1>Only subscribers with the Premium Access feature can access this content.</h1>

  return <h1>Our Exclusive Content</h1>
}

The following example demonstrates how to use has() to check if an organization has a permission.

app/page.tsx
import { auth } from '@clerk/nextjs/server'

export default async function Page() {
  // Use `auth()` helper to access the `has()` method
  const { has } = await auth()

  // Use `has()` method to check if organization has a Permission
  const hasPremiumAccessManage = has({ permission: 'premium_access:manage' })

  if (!hasPremiumAccessManage)
    return (
      <h1>Only subscribers with the Premium Access Manage permission can access this content.</h1>
    )

  return <h1>Our Exclusive Content</h1>
}

Example: Using <Protect>

The <Protect> component protects content or even entire routes by checking if the organization has been granted a specific type of access control (role, permission, feature, or plan). You can pass a fallback prop to <Protect> that will be rendered if the organization does not have the access control.

The following example demonstrates how to use <Protect> to protect a page by checking if the organization has a plan.

export default function ProtectPage() {
  return (
    <Protect
      plan="bronze"
      fallback={<p>Only subscribers to the Bronze plan can access this content.</p>}
    >
      {children}
    </Protect>
  )
}

The following example demonstrates how to use <Protect> to protect a page by checking if the organization has a feature.

export default function ProtectPage() {
  return (
    <Protect
      feature="premium_access"
      fallback={<p>Only subscribers with the Premium Access feature can access this content.</p>}
    >
      {children}
    </Protect>
  )
}

The following example demonstrates how to use <Protect> to protect a page by checking if the organization has a permission.

export default function ProtectPage() {
  return (
    <Protect
      permission="premium_access:manage"
      fallback={
        <p>Only subscribers with the Premium Access Manage permission can access this content.</p>
      }
    >
      {children}
    </Protect>
  )
}

Feedback

What did you think of this content?

Last updated on