1{2 "skill_name": "clerk-billing",3 "evals": [4 {5 "id": 1,6 "prompt": "i have a next.js saas app with clerk auth. i need to add a pricing page that shows subscription plans and lets users subscribe. connect clerk billing and render the pricing table.",7 "expected_output": "A /pricing route renders <PricingTable /> from @clerk/nextjs, with instructions to enable Billing in the Clerk Dashboard (dev gateway or Stripe for production) and a version-pinning note for the experimental APIs.",8 "scaffold": "nextjs-basic-auth",9 "files"
11 "Creates app/pricing/page.tsx that imports and renders <PricingTable /> from '@clerk/nextjs'",
12 "Recommends pinning the Clerk SDK and clerk-js versions because billing APIs are experimental",
13 "States that Billing must be enabled in the Clerk Dashboard → Billing → Settings as a MANUAL step BEFORE rendering <PricingTable /> (surfaces the dashboard.clerk.com link or the error signature 'cannot_render_billing_disabled')",
14 "Does not claim that the Clerk CLI or Backend API can enable billing (the billing_settings toggle is Dashboard-only today)",
15 "States that plans must be created in the matching tab (User Plans for B2C / Organization Plans for B2B); slugs are scoped per tab",
16 "Does not claim that plans sync to Stripe Products (Clerk Billing is a separate product from Stripe Billing)",
17 "Does not import '@clerk/billing' as a separate package (billing APIs ship inside @clerk/nextjs)",
18 "Does not suggest manually calling stripe.checkout.sessions.create or any Stripe API method directly",
19 "Does not claim that PricingTable redirects to Stripe Checkout (it opens Clerk's in-app checkout drawer)"
20 ]
21 },
22 {
23 "id": 2,
24 "prompt": "i need to protect my /dashboard/analytics route so only users on the 'pro' plan can access it. free users should be redirected to /pricing.",
25 "expected_output": "Server component at app/dashboard/analytics/page.tsx calls await auth(), uses has({ plan: 'pro' }) to check entitlement, and redirects free users to /pricing.",
26 "scaffold": "nextjs-basic-auth",
27 "files": [],
28 "assertions": [
29 "Imports auth from '@clerk/nextjs/server'",
30 "Calls await auth() (awaited, not sync)",
31 "Uses has({ plan: 'pro' }) to check the subscription",
32 "Calls redirect('/pricing') when the check fails",
33 "Does not read sessionClaims or JWT fields manually to check the plan"
34 ]
35 },
36 {
37 "id": 3,
38 "prompt": "my b2b saas lets teams subscribe via their organization. i need per-seat billing where adding org members automatically increments the seat count. show me the org-level plan check to protect team-only routes.",
39 "expected_output": "Server component checks orgId is present then uses has({ plan: 'org:team' }) to gate org-scoped routes. Explanation CORRECTS the user's mental model: Clerk Billing uses seat-LIMIT plans (membership caps with fixed per-plan pricing), not Stripe-style per-seat metered billing where the charge scales per member. Recommends tiered plans for charging larger orgs more, and renders the B2B pricing page with <PricingTable for=\"organization\" />.",
40 "scaffold": "nextjs-basic-auth",
41 "files": [],
42 "assertions": [
43 "Destructures both orgId and has from await auth()",
44 "Checks that orgId exists before checking the plan",
45 "Uses has({ plan: 'org:team' }) for the org-level entitlement",
46 "Redirects to a billing or pricing page when the org lacks the plan",
47 "Corrects the user's assumption of auto-incrementing per-seat billing, states Clerk uses seat-LIMIT plans (fixed price per plan + membership cap), not metered pricing that scales per member",
48 "Suggests creating tiered plans (e.g. starter 5 seats, team 10, enterprise unlimited) as the way to charge bigger orgs more",
49 "Recommends <PricingTable for=\"organization\" /> for the B2B pricing page",
50 "States that the plan must be created under the 'Organization Plans' tab, not 'User Plans'",
51 "Does not claim Clerk creates one Stripe subscription item per member, or that seat count equals items.length",
52 "Does not suggest building a manual member counter or seat tracking table"
53 ]
54 },
55 {
56 "id": 4,
57 "prompt": "i want to handle clerk billing webhook events so i can sync subscription status to my database. i need to handle when a subscription is created, when it gets canceled, and when a payment fails or goes past due.",
58 "expected_output": "POST handler calls verifyWebhook(req) from @clerk/nextjs/webhooks, branches on Clerk's dot-camelCase event names (subscription.created, subscriptionItem.canceled, subscriptionItem.pastDue), and proxy/middleware marks /api/webhooks as public.",
59 "scaffold": "nextjs-basic-auth",
60 "files": [],
61 "assertions": [
62 "Imports verifyWebhook from '@clerk/nextjs/webhooks' (the Clerk-provided helper)",
63 "Does NOT import Webhook from 'svix' directly, uses Clerk's verifyWebhook wrapper instead",
64 "Branches on the exact Clerk event name 'subscription.created'",
65 "Branches on the exact Clerk event name 'subscriptionItem.canceled' (camelCase, not 'subscription.canceled' or 'subscriptionItem.cancelled')",
66 "Branches on the exact Clerk event name 'subscriptionItem.pastDue' (camelCase 'pastDue', NOT snake_case 'past_due')",
67 "Does not use Stripe event names like 'customer.subscription.created', 'invoice.payment_failed', or 'customer.subscription.deleted'",
68 "If it inspects evt.data.object, matches against 'commerce_subscription' / 'commerce_subscription_item' / 'commerce_payer' / 'commerce_payment_attempt', not 'billing_*' variants (the wire format uses commerce_, not billing_)",
69 "Updates proxy.ts or middleware.ts to add /api/webhooks(.*) to createRouteMatcher so the webhook route is public",
70 "The clerkMiddleware callback is marked async to support await auth.protect()"
71 ]
72 },
73 {
74 "id": 5,
75 "prompt": "i need a billing settings page where users can see their current plan and upgrade or downgrade their subscription. show current status and let them change plans.",
76 "expected_output": "A protected billing page that renders <PricingTable /> for plan changes and displays the current plan using has({ plan }) or useSubscription().",
77 "scaffold": "nextjs-basic-auth",
78 "files": [],
79 "assertions": [
80 "Page is guarded by await auth() and requires authentication",
81 "Determines the current plan using has({ plan }) or the useSubscription() hook",
82 "Does not read sessionClaims.metadata.plan to display the current plan",
83 "Renders <PricingTable /> on the same page for plan changes",
84 "Does not implement a custom Stripe Customer Portal integration from scratch",
85 "Handles the case where the user has no active subscription"
86 ]
87 },
88 {
89 "id": 6,
90 "prompt": "i have three plans: free, starter, and pro. i want to gate individual features: 'export' is pro-only, 'analytics' is starter and pro. show how to conditionally render ui elements based on feature entitlements, not plan tiers.",
91 "expected_output": "Uses has({ feature: 'export' }) and has({ feature: 'analytics' }) (not has({ plan })), explains the decision rule for feature vs plan gating, warns about the billing-gates-permissions behavior, and notes that features are created per-plan (inside each plan's edit page in Dashboard → Billing → Plans), not in a global Features page.",
92 "scaffold": "nextjs-basic-auth",
93 "files": [],
94 "assertions": [
95 "Uses has({ feature: 'export' }) for the export gate (feature, not plan)",
96 "Uses has({ feature: 'analytics' }) for the analytics gate (feature, not plan)",
97 "Never uses has({ plan: ... }) to gate these specific capabilities",
98 "Explains the decision rule: use has({ feature }) for individual capabilities, use has({ plan }) only for tier-level gates like a Pro dashboard",
99 "States that features live inside each plan's edit page, not a global Features page (/billing/features does not exist)",
100 "States that the same feature slug can be attached to multiple plans, has({ feature }) matches if the active plan contains that slug",
101 "Warns that when Billing is enabled, has({ permission: ... }) returns false if the required Feature is not attached to the active Plan (billing gates permissions)",
102 "Does not suggest reading sessionClaims.metadata.plan or parsing plan tier strings directly"
103 ]
104 },
105 {
106 "id": 7,
107 "prompt": "users are subscribing but i'm not seeing their plan in the has() check. how do i debug why has({ plan: 'pro' }) returns false after a successful stripe checkout?",
108 "expected_output": "A debugging checklist: verify exact plan slug, confirm Billing is enabled (and Stripe connected for production), refresh the session after checkout, inspect Billing → Subscriptions in Dashboard.",
109 "scaffold": "nextjs-basic-auth",
110 "files": [],
111 "assertions": [
112 "Mentions that the plan slug in code must match exactly what is defined in Dashboard → Billing → Plans",
113 "Mentions that Billing must be enabled in Dashboard → Billing → Settings (dev gateway for development, Stripe for production)",
114 "Mentions that the session needs to refresh after checkout to include the new plan",
115 "Suggests inspecting Clerk Dashboard → Billing → Subscriptions to verify the subscription exists",
116 "Does not suggest building a custom subscription tracking system as a workaround"
117 ]
118 },
119 {
120 "id": 8,
121 "prompt": "i need a server action that creates a checkout session for upgrading a user from free to pro. the action should redirect to stripe checkout.",
122 "expected_output": "Explanation that PricingTable handles checkout; if a server action is shown, it redirects to a page that renders PricingTable rather than calling Stripe's checkout API.",
123 "scaffold": "nextjs-basic-auth",
124 "files": [],
125 "assertions": [
126 "Primary recommendation uses <PricingTable /> (or <CheckoutButton /> from @clerk/nextjs/experimental for a targeted single-plan flow)",
127 "Does not call stripe.checkout.sessions.create or equivalent Stripe API methods directly",
128 "If a server action is shown, it redirects to a /pricing route that renders PricingTable",
129 "States that PricingTable renders plan selection and opens Clerk's in-app checkout drawer (no redirect to Stripe Checkout)",
130 "Does not replace Clerk's billing integration with a raw Stripe implementation"
131 ]
132 },
133 {
134 "id": 9,
135 "prompt": "i'm trying to use clerk billing in my production app but i can't find the billing section in the dashboard and has({ plan }) always returns false. is billing broken?",
136 "expected_output": "Explanation that Clerk Billing must be explicitly enabled in Dashboard → Billing → Settings (this is Dashboard-only, the CLI and Backend API cannot toggle it). Mention that <PricingTable /> will throw 'cannot_render_billing_disabled' in development when this step is skipped.",
137 "scaffold": "nextjs-basic-auth",
138 "files": [],
139 "assertions": [
140 "States that Billing is not enabled by default and must be explicitly enabled in Dashboard → Billing → Settings",
141 "Surfaces the Dashboard link (dashboard.clerk.com) as the only way to toggle billing today",
142 "Mentions the 'cannot_render_billing_disabled' error code or the '<PricingTable /> cannot be rendered when billing is disabled' message as the developer-facing signal",
143 "Explains that has({ plan }) returns false when Billing is not enabled regardless of any Stripe configuration",
144 "Does not claim the Clerk CLI, clerk config patch, Backend API, or Platform API can enable billing",
145 "Does not diagnose this as a code bug before confirming Billing is enabled in Dashboard"
146 ]
147 },
148 {
149 "id": 10,
150 "prompt": "i want to offer a 14-day free trial on my pro plan that automatically converts to a paid subscription. how do i set this up with clerk billing?",
151 "expected_output": "Configure the trial period in Clerk Dashboard → Billing → Plans → Pro. Clerk handles the trial-to-paid conversion automatically (Stripe only processes the payment). Listen for subscriptionItem.freeTrialEnding to notify users.",
152 "scaffold": "nextjs-basic-auth",
153 "files": [],
154 "assertions": [
155 "Directs user to configure the trial period in Clerk Dashboard → Billing → Plans",
156 "States that Clerk handles the trial-to-paid conversion automatically (Stripe's role is payment processing only)",
157 "Mentions the subscriptionItem.freeTrialEnding webhook for notifying users before conversion",
158 "Recommends <PricingTable /> as the entry point for users to start the trial",
159 "Does not suggest building a custom trial tracking table or cron job"
160 ]
161 },
162 {
163 "id": 11,
164 "prompt": "i need to charge customers based on the number of api calls they make each month. how do i implement metered/usage-based billing with clerk?",
165 "expected_output": "Explanation that Clerk Billing currently supports fixed subscription plans (no native metered pricing). For usage-gated SaaS, use has({ feature }) to gate allotments and track consumption in your own datastore; do not bypass Clerk by configuring billing directly in Stripe, because Clerk Plans and Subscriptions do not sync with Stripe Billing.",
166 "scaffold": "nextjs-basic-auth",
167 "files": [],
168 "assertions": [
169 "Acknowledges that Clerk Billing primarily handles fixed subscription plans (no native metered primitive)",
170 "Does not claim Clerk Billing has a native metered pricing primitive",
171 "Does not instruct the user to configure metered pricing directly in Stripe and report usage via Stripe's usage records API as a replacement for Clerk Billing",
172 "Notes that Clerk Plans and Subscriptions do not sync to Stripe Billing, so bypassing Clerk to use Stripe metered billing would split the source of truth",
173 "Uses has({ feature }) to gate features based on plan allotments, with usage tracked in the developer's own datastore"
174 ]
175 },
176 {
177 "id": 12,
178 "prompt": "my enterprise customers need downloadable invoices and a billing portal where they can update payment methods. how do i build this with clerk?",
179 "expected_output": "Render <UserProfile /> (B2C) or <OrganizationProfile /> (B2B), both include built-in billing management with invoice history and payment methods.",
180 "scaffold": "nextjs-basic-auth",
181 "files": [],
182 "assertions": [
183 "Uses <UserProfile /> (B2C) or <OrganizationProfile /> (B2B) for billing management UI",
184 "States that Clerk provides built-in invoice history accessible through the profile component",
185 "States that payment method management is handled by the profile component",
186 "Does not build a custom Stripe Customer Portal integration from scratch",
187 "For enterprise B2B scenarios, recommends OrganizationProfile over UserProfile"