@dodopayments/opencode-plugin 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,501 @@
1
+ ---
2
+ name: billing-sdk
3
+ description: Guide for using BillingSDK - open-source React components for pricing tables, subscription management, and billing UI with Dodo Payments.
4
+ ---
5
+
6
+ # BillingSDK Integration
7
+
8
+ **Reference: [docs.dodopayments.com/developer-resources/billingsdk](https://docs.dodopayments.com/developer-resources/billingsdk) | [billingsdk.com](https://billingsdk.com)**
9
+
10
+ BillingSDK provides open-source, customizable React components for billing interfaces - pricing tables, subscription management, usage meters, and more.
11
+
12
+ ---
13
+
14
+ ## Overview
15
+
16
+ BillingSDK offers:
17
+ - **React Components**: Pre-built, customizable billing components
18
+ - **CLI Tooling**: Project initialization and component management
19
+ - **Framework Support**: Next.js, Express.js, Hono, Fastify, React
20
+ - **Payment Provider**: Full integration with Dodo Payments
21
+
22
+ ---
23
+
24
+ ## Quick Start Options
25
+
26
+ ### Option 1: New Project (Recommended)
27
+ Complete project setup with framework configuration and API routes:
28
+
29
+ ```bash
30
+ npx @billingsdk/cli init
31
+ ```
32
+
33
+ The CLI will:
34
+ - Configure your framework (Next.js App Router)
35
+ - Set up Dodo Payments integration
36
+ - Generate API routes for checkout, customers, webhooks
37
+ - Install dependencies
38
+ - Create configuration files
39
+
40
+ ### Option 2: Add to Existing Project
41
+ Add individual components using the CLI:
42
+
43
+ ```bash
44
+ npx @billingsdk/cli add pricing-table-one
45
+ npx @billingsdk/cli add subscription-management
46
+ npx @billingsdk/cli add usage-meter-circle
47
+ ```
48
+
49
+ ### Option 3: Manual via shadcn/ui
50
+ Install directly using shadcn registry:
51
+
52
+ ```bash
53
+ npx shadcn@latest add @billingsdk/pricing-table-one
54
+ ```
55
+
56
+ ---
57
+
58
+ ## CLI Reference
59
+
60
+ ### Initialize Project
61
+
62
+ ```bash
63
+ npx @billingsdk/cli init
64
+ ```
65
+
66
+ Interactive setup prompts:
67
+ 1. Select framework (Next.js, Express.js, Hono, Fastify, React)
68
+ 2. Select payment provider (Dodo Payments)
69
+ 3. Configure project settings
70
+
71
+ ### Add Components
72
+
73
+ ```bash
74
+ npx @billingsdk/cli add <component-name>
75
+ ```
76
+
77
+ **Available components:**
78
+ - `pricing-table-one` - Simple pricing table
79
+ - `pricing-table-two` - Feature-rich pricing table
80
+ - `subscription-management` - Manage active subscriptions
81
+ - `usage-meter-circle` - Circular usage visualization
82
+ - More components available...
83
+
84
+ ### What happens when adding:
85
+ 1. Downloads component from registry
86
+ 2. Installs files to `components/billingsdk/`
87
+ 3. Updates project configuration
88
+ 4. Installs additional dependencies
89
+
90
+ ---
91
+
92
+ ## Components
93
+
94
+ ### Pricing Table One
95
+
96
+ Simple, clean pricing table for displaying plans.
97
+
98
+ **Installation:**
99
+ ```bash
100
+ npx @billingsdk/cli add pricing-table-one
101
+ # or
102
+ npx shadcn@latest add @billingsdk/pricing-table-one
103
+ ```
104
+
105
+ **Usage:**
106
+ ```tsx
107
+ import { PricingTableOne } from "@/components/billingsdk/pricing-table-one";
108
+
109
+ const plans = [
110
+ {
111
+ id: 'prod_free',
112
+ name: 'Free',
113
+ price: 0,
114
+ interval: 'month',
115
+ features: ['5 projects', 'Basic support'],
116
+ },
117
+ {
118
+ id: 'prod_pro',
119
+ name: 'Pro',
120
+ price: 29,
121
+ interval: 'month',
122
+ features: ['Unlimited projects', 'Priority support', 'API access'],
123
+ popular: true,
124
+ },
125
+ {
126
+ id: 'prod_enterprise',
127
+ name: 'Enterprise',
128
+ price: 99,
129
+ interval: 'month',
130
+ features: ['Everything in Pro', 'Custom integrations', 'Dedicated support'],
131
+ },
132
+ ];
133
+
134
+ export function PricingPage() {
135
+ const handleSelectPlan = async (planId: string) => {
136
+ // Create checkout session
137
+ const response = await fetch('/api/checkout', {
138
+ method: 'POST',
139
+ headers: { 'Content-Type': 'application/json' },
140
+ body: JSON.stringify({ productId: planId }),
141
+ });
142
+
143
+ const { checkoutUrl } = await response.json();
144
+ window.location.href = checkoutUrl;
145
+ };
146
+
147
+ return (
148
+ <PricingTableOne
149
+ plans={plans}
150
+ onSelectPlan={handleSelectPlan}
151
+ />
152
+ );
153
+ }
154
+ ```
155
+
156
+ ### Pricing Table Two
157
+
158
+ Feature-comparison pricing table with toggle for monthly/yearly.
159
+
160
+ **Installation:**
161
+ ```bash
162
+ npx @billingsdk/cli add pricing-table-two
163
+ ```
164
+
165
+ **Usage:**
166
+ ```tsx
167
+ import { PricingTableTwo } from "@/components/billingsdk/pricing-table-two";
168
+
169
+ const plans = [
170
+ {
171
+ id: 'prod_starter_monthly',
172
+ yearlyId: 'prod_starter_yearly',
173
+ name: 'Starter',
174
+ monthlyPrice: 19,
175
+ yearlyPrice: 190,
176
+ features: [
177
+ { name: 'Projects', value: '10' },
178
+ { name: 'Storage', value: '5 GB' },
179
+ { name: 'Support', value: 'Email' },
180
+ ],
181
+ },
182
+ {
183
+ id: 'prod_pro_monthly',
184
+ yearlyId: 'prod_pro_yearly',
185
+ name: 'Pro',
186
+ monthlyPrice: 49,
187
+ yearlyPrice: 490,
188
+ popular: true,
189
+ features: [
190
+ { name: 'Projects', value: 'Unlimited' },
191
+ { name: 'Storage', value: '50 GB' },
192
+ { name: 'Support', value: 'Priority' },
193
+ ],
194
+ },
195
+ ];
196
+
197
+ export function PricingPage() {
198
+ return (
199
+ <PricingTableTwo
200
+ plans={plans}
201
+ onSelectPlan={(planId, billingInterval) => {
202
+ console.log(`Selected: ${planId}, Interval: ${billingInterval}`);
203
+ }}
204
+ />
205
+ );
206
+ }
207
+ ```
208
+
209
+ ### Subscription Management
210
+
211
+ Allow users to view and manage their subscription.
212
+
213
+ **Installation:**
214
+ ```bash
215
+ npx @billingsdk/cli add subscription-management
216
+ ```
217
+
218
+ **Usage:**
219
+ ```tsx
220
+ import { SubscriptionManagement } from "@/components/billingsdk/subscription-management";
221
+
222
+ export function AccountPage() {
223
+ const subscription = {
224
+ plan: 'Pro',
225
+ status: 'active',
226
+ currentPeriodEnd: '2025-02-21',
227
+ amount: 49,
228
+ interval: 'month',
229
+ };
230
+
231
+ return (
232
+ <SubscriptionManagement
233
+ subscription={subscription}
234
+ onManageBilling={async () => {
235
+ // Open customer portal
236
+ const response = await fetch('/api/portal', { method: 'POST' });
237
+ const { url } = await response.json();
238
+ window.location.href = url;
239
+ }}
240
+ onCancelSubscription={async () => {
241
+ if (confirm('Are you sure you want to cancel?')) {
242
+ await fetch('/api/subscription/cancel', { method: 'POST' });
243
+ }
244
+ }}
245
+ />
246
+ );
247
+ }
248
+ ```
249
+
250
+ ### Usage Meter
251
+
252
+ Display usage-based billing metrics.
253
+
254
+ **Installation:**
255
+ ```bash
256
+ npx @billingsdk/cli add usage-meter-circle
257
+ ```
258
+
259
+ **Usage:**
260
+ ```tsx
261
+ import { UsageMeterCircle } from "@/components/billingsdk/usage-meter-circle";
262
+
263
+ export function UsageDashboard() {
264
+ return (
265
+ <div className="grid grid-cols-3 gap-4">
266
+ <UsageMeterCircle
267
+ label="API Calls"
268
+ current={8500}
269
+ limit={10000}
270
+ unit="calls"
271
+ />
272
+ <UsageMeterCircle
273
+ label="Storage"
274
+ current={3.2}
275
+ limit={5}
276
+ unit="GB"
277
+ />
278
+ <UsageMeterCircle
279
+ label="Bandwidth"
280
+ current={45}
281
+ limit={100}
282
+ unit="GB"
283
+ />
284
+ </div>
285
+ );
286
+ }
287
+ ```
288
+
289
+ ---
290
+
291
+ ## Next.js Integration
292
+
293
+ ### Project Structure (after `init`)
294
+
295
+ ```
296
+ your-project/
297
+ ├── app/
298
+ │ ├── api/
299
+ │ │ ├── checkout/
300
+ │ │ │ └── route.ts
301
+ │ │ ├── portal/
302
+ │ │ │ └── route.ts
303
+ │ │ └── webhooks/
304
+ │ │ └── dodo/
305
+ │ │ └── route.ts
306
+ │ └── pricing/
307
+ │ └── page.tsx
308
+ ├── components/
309
+ │ └── billingsdk/
310
+ │ ├── pricing-table-one.tsx
311
+ │ └── subscription-management.tsx
312
+ ├── lib/
313
+ │ ├── dodo.ts
314
+ │ └── billingsdk-config.ts
315
+ └── .env.local
316
+ ```
317
+
318
+ ### Generated API Routes
319
+
320
+ **Checkout Route (`app/api/checkout/route.ts`):**
321
+ ```typescript
322
+ import { NextRequest, NextResponse } from 'next/server';
323
+ import { dodo } from '@/lib/dodo';
324
+
325
+ export async function POST(req: NextRequest) {
326
+ const { productId, email } = await req.json();
327
+
328
+ const session = await dodo.checkoutSessions.create({
329
+ product_cart: [{ product_id: productId, quantity: 1 }],
330
+ customer: { email },
331
+ return_url: `${process.env.NEXT_PUBLIC_APP_URL}/success`,
332
+ });
333
+
334
+ return NextResponse.json({ checkoutUrl: session.checkout_url });
335
+ }
336
+ ```
337
+
338
+ **Portal Route (`app/api/portal/route.ts`):**
339
+ ```typescript
340
+ import { NextRequest, NextResponse } from 'next/server';
341
+ import { dodo } from '@/lib/dodo';
342
+ import { getSession } from '@/lib/auth';
343
+
344
+ export async function POST(req: NextRequest) {
345
+ const session = await getSession();
346
+
347
+ const portal = await dodo.customers.createPortalSession({
348
+ customer_id: session.user.customerId,
349
+ return_url: `${process.env.NEXT_PUBLIC_APP_URL}/account`,
350
+ });
351
+
352
+ return NextResponse.json({ url: portal.url });
353
+ }
354
+ ```
355
+
356
+ ### Configuration File
357
+
358
+ **`lib/billingsdk-config.ts`:**
359
+ ```typescript
360
+ export const plans = [
361
+ {
362
+ id: process.env.NEXT_PUBLIC_PLAN_FREE_ID!,
363
+ name: 'Free',
364
+ description: 'Perfect for trying out',
365
+ price: 0,
366
+ interval: 'month' as const,
367
+ features: [
368
+ '5 projects',
369
+ '1 GB storage',
370
+ 'Community support',
371
+ ],
372
+ },
373
+ {
374
+ id: process.env.NEXT_PUBLIC_PLAN_PRO_ID!,
375
+ name: 'Pro',
376
+ description: 'For professionals',
377
+ price: 29,
378
+ interval: 'month' as const,
379
+ popular: true,
380
+ features: [
381
+ 'Unlimited projects',
382
+ '50 GB storage',
383
+ 'Priority support',
384
+ 'API access',
385
+ ],
386
+ },
387
+ ];
388
+
389
+ export const config = {
390
+ returnUrl: process.env.NEXT_PUBLIC_APP_URL + '/success',
391
+ portalReturnUrl: process.env.NEXT_PUBLIC_APP_URL + '/account',
392
+ };
393
+ ```
394
+
395
+ ---
396
+
397
+ ## Customization
398
+
399
+ ### Styling with Tailwind
400
+
401
+ Components use Tailwind CSS and shadcn/ui patterns. Customize via:
402
+
403
+ 1. **Theme variables** in `globals.css`
404
+ 2. **Direct class overrides** on components
405
+ 3. **Component source modification** (files are local)
406
+
407
+ **Example - Custom colors:**
408
+ ```css
409
+ /* globals.css */
410
+ @layer base {
411
+ :root {
412
+ --primary: 220 90% 56%;
413
+ --primary-foreground: 0 0% 100%;
414
+ }
415
+ }
416
+ ```
417
+
418
+ ### Component Props
419
+
420
+ Most components accept standard styling props:
421
+
422
+ ```tsx
423
+ <PricingTableOne
424
+ plans={plans}
425
+ onSelectPlan={handleSelect}
426
+ className="max-w-4xl mx-auto"
427
+ containerClassName="gap-8"
428
+ cardClassName="border-2"
429
+ />
430
+ ```
431
+
432
+ ---
433
+
434
+ ## Environment Variables
435
+
436
+ ```bash
437
+ # .env.local
438
+
439
+ # Dodo Payments
440
+ DODO_PAYMENTS_API_KEY=sk_live_xxxxx
441
+ DODO_PAYMENTS_WEBHOOK_SECRET=whsec_xxxxx
442
+
443
+ # Product IDs (from dashboard)
444
+ NEXT_PUBLIC_PLAN_FREE_ID=prod_xxxxx
445
+ NEXT_PUBLIC_PLAN_PRO_ID=prod_xxxxx
446
+ NEXT_PUBLIC_PLAN_ENTERPRISE_ID=prod_xxxxx
447
+
448
+ # App
449
+ NEXT_PUBLIC_APP_URL=https://yoursite.com
450
+ ```
451
+
452
+ ---
453
+
454
+ ## Best Practices
455
+
456
+ ### 1. Use Product IDs from Environment
457
+ Keep product IDs in environment variables for easy staging/production switching.
458
+
459
+ ### 2. Handle Loading States
460
+ Components should show loading states during checkout:
461
+
462
+ ```tsx
463
+ const [loading, setLoading] = useState(false);
464
+
465
+ const handleSelect = async (planId: string) => {
466
+ setLoading(true);
467
+ try {
468
+ const response = await fetch('/api/checkout', {...});
469
+ const { checkoutUrl } = await response.json();
470
+ window.location.href = checkoutUrl;
471
+ } finally {
472
+ setLoading(false);
473
+ }
474
+ };
475
+ ```
476
+
477
+ ### 3. Server-Side Data Fetching
478
+ Fetch subscription data server-side when possible:
479
+
480
+ ```tsx
481
+ // app/account/page.tsx
482
+ import { getSubscription } from '@/lib/subscription';
483
+
484
+ export default async function AccountPage() {
485
+ const subscription = await getSubscription();
486
+
487
+ return <SubscriptionManagement subscription={subscription} />;
488
+ }
489
+ ```
490
+
491
+ ### 4. Implement Webhooks
492
+ Always use webhooks as source of truth for subscription status, not client-side data.
493
+
494
+ ---
495
+
496
+ ## Resources
497
+
498
+ - [BillingSDK Documentation](https://billingsdk.com/docs)
499
+ - [Dodo Payments Integration](https://docs.dodopayments.com/developer-resources/billingsdk)
500
+ - [Component Gallery](https://billingsdk.com/docs/components)
501
+ - [GitHub Repository](https://github.com/dodopayments/billingsdk)