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.

referencesbilling-components.md

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

Billing Components

PricingTable

The primary billing UI component. Renders subscription plans and opens Clerk's in-app checkout drawer when a user selects a plan.

import { PricingTable } from '@clerk/nextjs'

export default function PricingPage() {
	return <PricingTable />
}

What it does:

  • Fetches plan data from Clerk Dashboard configuration
  • Renders plan cards with features, pricing, and CTA buttons
  • Opens Clerk's in-app checkout drawer on plan selection
  • Shows current plan for subscribed users with upgrade/downgrade options

Key behaviors:

  • Respects the active entity by default: user subscription for personal accounts, org subscription in org context. Override with for.
  • For an account-management UI that includes plan switching, cancellations, payment methods, and invoices, render <UserProfile /> (B2C) or <OrganizationProfile /> (B2B) instead. Use <PricingTable /> standalone only when you need a dedicated pricing page.

Props (all optional):

Prop Type Description
appearance Appearance Style overrides for the component.
checkoutProps { appearance: Appearance } Style overrides for the checkout drawer.
collapseFeatures boolean Start with features collapsed. Requires layout: 'default'. Defaults to false.
ctaPosition 'top' | 'bottom' Placement of the CTA button. Requires layout: 'default'. Defaults to 'bottom'.
fallback JSX UI to show while the pricing table is loading.
for 'user' | 'organization' Which subscriber the table targets. Defaults to 'user'. Use 'organization' for B2B.
newSubscriptionRedirectUrl string URL to navigate to after checkout completes.

For most cases, use <PricingTable /> with no props (or just for="organization" for B2B).

CheckoutButton

For custom checkout UX outside <PricingTable />, use <CheckoutButton /> from @clerk/nextjs/experimental. It opens the same checkout drawer for a specific planId. Must be wrapped in <Show when="signed-in">.

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

export function UpgradeCTA() {
	return (
		<Show when="signed-in">
			<CheckoutButton
				planId="cplan_xxx"
				planPeriod="annual"
				for="user"
				newSubscriptionRedirectUrl="/dashboard"
				onSubscriptionComplete={() => console.log('subscribed')}
			/>
		</Show>
	)
}

Key props: planId (required), planPeriod: 'month' | 'annual', for: 'user' | 'organization', onSubscriptionComplete, newSubscriptionRedirectUrl, checkoutProps: { appearance }. Throws if for="organization" is set with no active Organization.

has(), Plan and Feature Checks

has() is returned by auth() (server) and useAuth() (client). It checks subscription plans and feature entitlements.

Server usage

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

const { has } = await auth()

has({ plan: 'pro' })        // true if user/org is on 'pro' plan
has({ feature: 'export' })  // true if user/org has 'export' feature entitlement

Client usage

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

const { has } = useAuth()
has?.({ plan: 'pro' })       // optional chaining, may be undefined before hydration
has?.({ feature: 'export' })

Combining with role checks

const { has, orgRole } = await auth()

const canManageBilling = has({ plan: 'pro' }) && orgRole === 'org:admin'

What has() checks

has() checks the active session claims. Plans and features are embedded in the Clerk session token after a subscription is active. The check does NOT make a network request.

If a user subscribes and then has() returns false, the session token needs to refresh. This happens automatically on the next page load or after calling clerk.session.reload() on the client.

Show Component (Billing-aware)

import { Show } from '@clerk/nextjs'

<Show when={{ plan: 'pro' }}>
	<ProFeatures />
</Show>

<Show when={{ feature: 'analytics' }}>
	<AnalyticsDashboard />
</Show>

<Show> accepts plan and feature props in addition to role and permission. Renders children only if the condition is met.

Import Reference

// Stable
import { PricingTable, Show, useAuth } from '@clerk/nextjs'
import { auth } from '@clerk/nextjs/server'

// Experimental (Billing)
import { CheckoutButton, useSubscription } from '@clerk/nextjs/experimental'

Stable billing primitives (PricingTable, has() via auth() / useAuth(), <Show>) live in @clerk/nextjs. Experimental hooks and components (useSubscription, CheckoutButton, SubscriptionDetailsButton, PlanDetailsButton) live in @clerk/nextjs/experimental. No separate billing package needed.

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.