All skills
clerk avatar

/clerk-billing

@47c55cd official
by clerkclerk/skills83 stars
5

Clerk Billing for subscription management - render Clerk's PricingTable and in-app checkout drawer, configure subscription plans, seat-limit plans for B2B, feature entitlements with has(), and billing webhooks. Use for SaaS monetization, plan gating, checkout flows, trials, invoicing, and subscription lifecycle management.

Use this Skill: https://skilld.dev/gh/clerk/skills/clerk-billing

This session only. Nothing lands on disk.

referencesb2c-patterns.md

≈1k tokens on demand. Your agent reads this file only when SKILL.md points to it.

B2C Billing Patterns

Overview

B2C billing in Clerk attaches subscriptions to individual users. Each user gets their own Clerk subscription. Use has({ plan }) on the user session.

Prerequisite: personal accounts must be allowed. If Organizations are enabled, open Dashboard → Organizations settings and set Membership options → "Membership optional". In "Membership required" mode personal accounts are disabled, <PricingTable /> silently excludes any user without an active org (no error, no console warning). Check this first when a user reports "subscribe does nothing."

Plans for B2C must be created as User Plans (Dashboard → Billing → Plans → User Plans tab, or clerk config patch with billing.plans). A pro plan registered as an Organization Plan is a separate entity and won't appear in <PricingTable />. Plan type isn't changeable, recreate if misplaced.

Core Pattern: User Plan Check

import { auth } from '@clerk/nextjs/server'
import { redirect } from 'next/navigation'

export default async function ProDashboard() {
	const { userId, has } = await auth()

	if (!userId) {
		redirect('/sign-in')
	}

	if (!has({ plan: 'pro' })) {
		redirect('/pricing')
	}

	return <ProContent />
}

Tiered Feature Gating

Prefer has({ feature }) over has({ plan }) for capability gating: features can be reattached between plans without a code deploy.

import { auth } from '@clerk/nextjs/server'

export default async function AppPage() {
	const { has } = await auth()

	const canAnalytics = has({ feature: 'analytics' })
	const canExport = has({ feature: 'export' })
	const canApi = has({ feature: 'api_access' })

	return (
		<div>
			<BasicFeature />
			{canAnalytics && <AnalyticsDashboard />}
			{canExport && <ExportButton />}
			{canApi && <APIAccess />}
		</div>
	)
}

Redirect Pattern After Checkout

After checkout completes in Clerk's drawer, Clerk refreshes the session with updated plan data. Pass newSubscriptionRedirectUrl to <PricingTable /> to navigate after the user confirms. For custom post-checkout logic:

// app/billing/success/page.tsx
import { auth } from '@clerk/nextjs/server'
import { redirect } from 'next/navigation'

export default async function BillingSuccessPage() {
	const { has } = await auth()

	if (!has({ plan: 'pro' })) {
		return <p>Waiting for subscription to activate...</p>
	}

	redirect('/dashboard')
}

Account Billing Page

Use <UserProfile /> for the user account billing UI. It renders the current plan, subscription status, payment methods, invoices, and the upgrade / cancellation flow with no custom code:

import { UserProfile } from '@clerk/nextjs'

export default function AccountPage() {
	return <UserProfile />
}

User Plans configured in Dashboard → Billing → Plans automatically appear inside <UserProfile /> (in the Plans section). Cancellation and plan switching are handled in the same drawer. Only build a custom billing page when you need branded layouts or to embed <PricingTable /> outside the UserProfile shell.

For richer subscription details in client components (status, renewal date, trial end), use the useSubscription() hook instead of reading JWT claims:

'use client'
import { useSubscription } from '@clerk/nextjs/experimental'

export function BillingSummary() {
	const { data, isLoading } = useSubscription()
	if (isLoading || !data) return null
	return (
		<p>
			Status: {data.status}
			{data.nextPayment && ` (renews ${data.nextPayment.date.toLocaleDateString()})`}
		</p>
	)
}

Client-Side Feature Gating

For interactive components that need plan checks:

'use client'
import { useAuth } from '@clerk/nextjs'

export function ExportButton() {
	const { has } = useAuth()

	if (!has?.({ plan: 'pro' })) {
		return (
			<button disabled title="Pro plan required">
				Export (Pro)
			</button>
		)
	}

	return <button onClick={handleExport}>Export</button>
}

Note: has may be undefined on initial render. Use optional chaining has?.().

Source: SKILL.md on GitHub

1 warning6d3 checks · Risk SAFE
  • Gen Agent Trust Hub6d

    The skill provides comprehensive instructions for integrating Clerk Billing into Next.js applications, including subscription management, UI components, and webhook handling. It utilizes official Clerk CLI tools and SDKs and emphasizes security best practices such as webhook signature verification.

  • Socket6d

    No alerts

  • Snyk6d

    Risk: MEDIUM · 1 issue

Signed by skilld at 47c55cd. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated last week
What it can do
Network
metadata
{
  "author": "clerk",
  "version": "1.1.0"
}
All 1 allowed tools
WebFetch
Other metadata
compatibility
Requires NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, CLERK_SECRET_KEY, and CLERK_WEBHOOK_SIGNING_SECRET. Billing must be enabled in Clerk Dashboard → Billing. Development instances can use the shared Clerk development gateway; production instances require a Stripe account for payment processing.
  • Next.js
  • clerk
  • billing
  • saas
  • subscriptions
  • pricing
  • stripe
  • feature-gating
  • b2b
  • webhooks

README badge

README badge for clerk/skills/clerk-billing

Configures subscription plans, seat-limit tiers for B2B, and feature entitlements in Clerk, then gates access via `has({ plan })` and `has({ feature })` checks. Renders pricing tables and checkout flows with `<PricingTable />`, manages billing webhooks for subscription lifecycle, and supports both user and organization subscriptions via Next.js Server and Client Components.

Generated from the current SKILL.md.

Do I need a Stripe account to use Clerk Billing?
No for development. Dev instances can use Clerk's shared development gateway. Production requires a Stripe account for payment processing only.
What's the difference between has({ plan }) and has({ feature })?
Use has({ feature }) to gate specific capabilities like export or analytics. Use has({ plan }) to gate by subscription tier. Features are assigned to plans and scoped per plan.
Can I configure billing plans programmatically without the Dashboard?
Yes. Use clerk enable billing, clerk config pull, and clerk config patch commands to manage plans and features via CLI, or make raw PATCH requests to the PLAPI.
Does this support B2B organization subscriptions and seat limits?
Yes. Use <PricingTable for="organization" /> to render org-level plans, and configure seat-limit plans to enforce membership caps that Clerk enforces at invite time.
What happens if I render <PricingTable /> before enabling Billing?
In development it throws a cannot_render_billing_disabled error. In production it renders empty. Billing must be enabled in the Dashboard or via clerk enable billing first.

Generated from the current SKILL.md. These answers refresh after source changes.