billing-sdk by dodopayments/skills
npx skills add https://github.com/dodopayments/skills --skill billing-sdk参考:docs.dodopayments.com/developer-resources/billingsdk | billingsdk.com
BillingSDK 为计费界面提供了开源、可定制的 React 组件 - 包括价格表、订阅管理、用量仪表等。
BillingSDK 提供:
包含框架配置和 API 路由的完整项目设置:
npx @billingsdk/cli init
CLI 将:
使用 CLI 添加单个组件:
npx @billingsdk/cli add pricing-table-one
npx @billingsdk/cli add subscription-management
npx @billingsdk/cli add usage-meter-circle
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
使用 shadcn 注册表直接安装:
npx shadcn@latest add @billingsdk/pricing-table-one
npx @billingsdk/cli init
交互式设置提示:
npx @billingsdk/cli add <component-name>
可用组件:
pricing-table-one - 简洁的价格表pricing-table-two - 功能丰富的价格表subscription-management - 管理活跃订阅usage-meter-circle - 环形用量可视化components/billingsdk/用于展示套餐的简洁、清晰的价格表。
安装:
npx @billingsdk/cli add pricing-table-one
# 或
npx shadcn@latest add @billingsdk/pricing-table-one
用法:
import { PricingTableOne } from "@/components/billingsdk/pricing-table-one";
const plans = [
{
id: 'prod_free',
name: 'Free',
price: 0,
interval: 'month',
features: ['5 projects', 'Basic support'],
},
{
id: 'prod_pro',
name: 'Pro',
price: 29,
interval: 'month',
features: ['Unlimited projects', 'Priority support', 'API access'],
popular: true,
},
{
id: 'prod_enterprise',
name: 'Enterprise',
price: 99,
interval: 'month',
features: ['Everything in Pro', 'Custom integrations', 'Dedicated support'],
},
];
export function PricingPage() {
const handleSelectPlan = async (planId: string) => {
// 创建结账会话
const response = await fetch('/api/checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ productId: planId }),
});
const { checkoutUrl } = await response.json();
window.location.href = checkoutUrl;
};
return (
<PricingTableOne
plans={plans}
onSelectPlan={handleSelectPlan}
/>
);
}
包含月/年切换功能的特性对比价格表。
安装:
npx @billingsdk/cli add pricing-table-two
用法:
import { PricingTableTwo } from "@/components/billingsdk/pricing-table-two";
const plans = [
{
id: 'prod_starter_monthly',
yearlyId: 'prod_starter_yearly',
name: 'Starter',
monthlyPrice: 19,
yearlyPrice: 190,
features: [
{ name: 'Projects', value: '10' },
{ name: 'Storage', value: '5 GB' },
{ name: 'Support', value: 'Email' },
],
},
{
id: 'prod_pro_monthly',
yearlyId: 'prod_pro_yearly',
name: 'Pro',
monthlyPrice: 49,
yearlyPrice: 490,
popular: true,
features: [
{ name: 'Projects', value: 'Unlimited' },
{ name: 'Storage', value: '50 GB' },
{ name: 'Support', value: 'Priority' },
],
},
];
export function PricingPage() {
return (
<PricingTableTwo
plans={plans}
onSelectPlan={(planId, billingInterval) => {
console.log(`Selected: ${planId}, Interval: ${billingInterval}`);
}}
/>
);
}
允许用户查看和管理其订阅。
安装:
npx @billingsdk/cli add subscription-management
用法:
import { SubscriptionManagement } from "@/components/billingsdk/subscription-management";
export function AccountPage() {
const subscription = {
plan: 'Pro',
status: 'active',
currentPeriodEnd: '2025-02-21',
amount: 49,
interval: 'month',
};
return (
<SubscriptionManagement
subscription={subscription}
onManageBilling={async () => {
// 打开客户门户
const response = await fetch('/api/portal', { method: 'POST' });
const { url } = await response.json();
window.location.href = url;
}}
onCancelSubscription={async () => {
if (confirm('Are you sure you want to cancel?')) {
await fetch('/api/subscription/cancel', { method: 'POST' });
}
}}
/>
);
}
展示基于用量的计费指标。
安装:
npx @billingsdk/cli add usage-meter-circle
用法:
import { UsageMeterCircle } from "@/components/billingsdk/usage-meter-circle";
export function UsageDashboard() {
return (
<div className="grid grid-cols-3 gap-4">
<UsageMeterCircle
label="API Calls"
current={8500}
limit={10000}
unit="calls"
/>
<UsageMeterCircle
label="Storage"
current={3.2}
limit={5}
unit="GB"
/>
<UsageMeterCircle
label="Bandwidth"
current={45}
limit={100}
unit="GB"
/>
</div>
);
}
init 之后)your-project/
├── app/
│ ├── api/
│ │ ├── checkout/
│ │ │ └── route.ts
│ │ ├── portal/
│ │ │ └── route.ts
│ │ └── webhooks/
│ │ └── dodo/
│ │ └── route.ts
│ └── pricing/
│ └── page.tsx
├── components/
│ └── billingsdk/
│ ├── pricing-table-one.tsx
│ └── subscription-management.tsx
├── lib/
│ ├── dodo.ts
│ └── billingsdk-config.ts
└── .env.local
结账路由 (app/api/checkout/route.ts):
import { NextRequest, NextResponse } from 'next/server';
import { dodo } from '@/lib/dodo';
export async function POST(req: NextRequest) {
const { productId, email } = await req.json();
const session = await dodo.checkoutSessions.create({
product_cart: [{ product_id: productId, quantity: 1 }],
customer: { email },
return_url: `${process.env.NEXT_PUBLIC_APP_URL}/success`,
});
return NextResponse.json({ checkoutUrl: session.checkout_url });
}
门户路由 (app/api/portal/route.ts):
import { NextRequest, NextResponse } from 'next/server';
import { dodo } from '@/lib/dodo';
import { getSession } from '@/lib/auth';
export async function POST(req: NextRequest) {
const session = await getSession();
const portal = await dodo.customers.createPortalSession({
customer_id: session.user.customerId,
return_url: `${process.env.NEXT_PUBLIC_APP_URL}/account`,
});
return NextResponse.json({ url: portal.url });
}
lib/billingsdk-config.ts:
export const plans = [
{
id: process.env.NEXT_PUBLIC_PLAN_FREE_ID!,
name: 'Free',
description: 'Perfect for trying out',
price: 0,
interval: 'month' as const,
features: [
'5 projects',
'1 GB storage',
'Community support',
],
},
{
id: process.env.NEXT_PUBLIC_PLAN_PRO_ID!,
name: 'Pro',
description: 'For professionals',
price: 29,
interval: 'month' as const,
popular: true,
features: [
'Unlimited projects',
'50 GB storage',
'Priority support',
'API access',
],
},
];
export const config = {
returnUrl: process.env.NEXT_PUBLIC_APP_URL + '/success',
portalReturnUrl: process.env.NEXT_PUBLIC_APP_URL + '/account',
};
组件使用 Tailwind CSS 和 shadcn/ui 模式。可通过以下方式自定义:
globals.css 中示例 - 自定义颜色:
/* globals.css */
@layer base {
:root {
--primary: 220 90% 56%;
--primary-foreground: 0 0% 100%;
}
}
大多数组件接受标准样式属性:
<PricingTableOne
plans={plans}
onSelectPlan={handleSelect}
className="max-w-4xl mx-auto"
containerClassName="gap-8"
cardClassName="border-2"
/>
# .env.local
# Dodo Payments
DODO_PAYMENTS_API_KEY=sk_live_xxxxx
DODO_PAYMENTS_WEBHOOK_SECRET=whsec_xxxxx
# Product IDs (from dashboard)
NEXT_PUBLIC_PLAN_FREE_ID=prod_xxxxx
NEXT_PUBLIC_PLAN_PRO_ID=prod_xxxxx
NEXT_PUBLIC_PLAN_ENTERPRISE_ID=prod_xxxxx
# App
NEXT_PUBLIC_APP_URL=https://yoursite.com
将产品 ID 保存在环境变量中,便于在暂存/生产环境之间切换。
组件在结账过程中应显示加载状态:
const [loading, setLoading] = useState(false);
const handleSelect = async (planId: string) => {
setLoading(true);
try {
const response = await fetch('/api/checkout', {...});
const { checkoutUrl } = await response.json();
window.location.href = checkoutUrl;
} finally {
setLoading(false);
}
};
尽可能在服务器端获取订阅数据:
// app/account/page.tsx
import { getSubscription } from '@/lib/subscription';
export default async function AccountPage() {
const subscription = await getSubscription();
return <SubscriptionManagement subscription={subscription} />;
}
始终将 Webhook 作为订阅状态的唯一真实来源,而不是客户端数据。
每周安装量
139
仓库
GitHub Stars
7
首次出现
2026年1月21日
安全审计
安装于
opencode114
gemini-cli112
codex106
github-copilot101
claude-code92
cursor86
Reference:docs.dodopayments.com/developer-resources/billingsdk | billingsdk.com
BillingSDK provides open-source, customizable React components for billing interfaces - pricing tables, subscription management, usage meters, and more.
BillingSDK offers:
Complete project setup with framework configuration and API routes:
npx @billingsdk/cli init
The CLI will:
Add individual components using the CLI:
npx @billingsdk/cli add pricing-table-one
npx @billingsdk/cli add subscription-management
npx @billingsdk/cli add usage-meter-circle
Install directly using shadcn registry:
npx shadcn@latest add @billingsdk/pricing-table-one
npx @billingsdk/cli init
Interactive setup prompts:
npx @billingsdk/cli add <component-name>
Available components:
pricing-table-one - Simple pricing tablepricing-table-two - Feature-rich pricing tablesubscription-management - Manage active subscriptionsusage-meter-circle - Circular usage visualizationcomponents/billingsdk/Simple, clean pricing table for displaying plans.
Installation:
npx @billingsdk/cli add pricing-table-one
# or
npx shadcn@latest add @billingsdk/pricing-table-one
Usage:
import { PricingTableOne } from "@/components/billingsdk/pricing-table-one";
const plans = [
{
id: 'prod_free',
name: 'Free',
price: 0,
interval: 'month',
features: ['5 projects', 'Basic support'],
},
{
id: 'prod_pro',
name: 'Pro',
price: 29,
interval: 'month',
features: ['Unlimited projects', 'Priority support', 'API access'],
popular: true,
},
{
id: 'prod_enterprise',
name: 'Enterprise',
price: 99,
interval: 'month',
features: ['Everything in Pro', 'Custom integrations', 'Dedicated support'],
},
];
export function PricingPage() {
const handleSelectPlan = async (planId: string) => {
// Create checkout session
const response = await fetch('/api/checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ productId: planId }),
});
const { checkoutUrl } = await response.json();
window.location.href = checkoutUrl;
};
return (
<PricingTableOne
plans={plans}
onSelectPlan={handleSelectPlan}
/>
);
}
Feature-comparison pricing table with toggle for monthly/yearly.
Installation:
npx @billingsdk/cli add pricing-table-two
Usage:
import { PricingTableTwo } from "@/components/billingsdk/pricing-table-two";
const plans = [
{
id: 'prod_starter_monthly',
yearlyId: 'prod_starter_yearly',
name: 'Starter',
monthlyPrice: 19,
yearlyPrice: 190,
features: [
{ name: 'Projects', value: '10' },
{ name: 'Storage', value: '5 GB' },
{ name: 'Support', value: 'Email' },
],
},
{
id: 'prod_pro_monthly',
yearlyId: 'prod_pro_yearly',
name: 'Pro',
monthlyPrice: 49,
yearlyPrice: 490,
popular: true,
features: [
{ name: 'Projects', value: 'Unlimited' },
{ name: 'Storage', value: '50 GB' },
{ name: 'Support', value: 'Priority' },
],
},
];
export function PricingPage() {
return (
<PricingTableTwo
plans={plans}
onSelectPlan={(planId, billingInterval) => {
console.log(`Selected: ${planId}, Interval: ${billingInterval}`);
}}
/>
);
}
Allow users to view and manage their subscription.
Installation:
npx @billingsdk/cli add subscription-management
Usage:
import { SubscriptionManagement } from "@/components/billingsdk/subscription-management";
export function AccountPage() {
const subscription = {
plan: 'Pro',
status: 'active',
currentPeriodEnd: '2025-02-21',
amount: 49,
interval: 'month',
};
return (
<SubscriptionManagement
subscription={subscription}
onManageBilling={async () => {
// Open customer portal
const response = await fetch('/api/portal', { method: 'POST' });
const { url } = await response.json();
window.location.href = url;
}}
onCancelSubscription={async () => {
if (confirm('Are you sure you want to cancel?')) {
await fetch('/api/subscription/cancel', { method: 'POST' });
}
}}
/>
);
}
Display usage-based billing metrics.
Installation:
npx @billingsdk/cli add usage-meter-circle
Usage:
import { UsageMeterCircle } from "@/components/billingsdk/usage-meter-circle";
export function UsageDashboard() {
return (
<div className="grid grid-cols-3 gap-4">
<UsageMeterCircle
label="API Calls"
current={8500}
limit={10000}
unit="calls"
/>
<UsageMeterCircle
label="Storage"
current={3.2}
limit={5}
unit="GB"
/>
<UsageMeterCircle
label="Bandwidth"
current={45}
limit={100}
unit="GB"
/>
</div>
);
}
init)your-project/
├── app/
│ ├── api/
│ │ ├── checkout/
│ │ │ └── route.ts
│ │ ├── portal/
│ │ │ └── route.ts
│ │ └── webhooks/
│ │ └── dodo/
│ │ └── route.ts
│ └── pricing/
│ └── page.tsx
├── components/
│ └── billingsdk/
│ ├── pricing-table-one.tsx
│ └── subscription-management.tsx
├── lib/
│ ├── dodo.ts
│ └── billingsdk-config.ts
└── .env.local
Checkout Route (app/api/checkout/route.ts):
import { NextRequest, NextResponse } from 'next/server';
import { dodo } from '@/lib/dodo';
export async function POST(req: NextRequest) {
const { productId, email } = await req.json();
const session = await dodo.checkoutSessions.create({
product_cart: [{ product_id: productId, quantity: 1 }],
customer: { email },
return_url: `${process.env.NEXT_PUBLIC_APP_URL}/success`,
});
return NextResponse.json({ checkoutUrl: session.checkout_url });
}
Portal Route (app/api/portal/route.ts):
import { NextRequest, NextResponse } from 'next/server';
import { dodo } from '@/lib/dodo';
import { getSession } from '@/lib/auth';
export async function POST(req: NextRequest) {
const session = await getSession();
const portal = await dodo.customers.createPortalSession({
customer_id: session.user.customerId,
return_url: `${process.env.NEXT_PUBLIC_APP_URL}/account`,
});
return NextResponse.json({ url: portal.url });
}
lib/billingsdk-config.ts:
export const plans = [
{
id: process.env.NEXT_PUBLIC_PLAN_FREE_ID!,
name: 'Free',
description: 'Perfect for trying out',
price: 0,
interval: 'month' as const,
features: [
'5 projects',
'1 GB storage',
'Community support',
],
},
{
id: process.env.NEXT_PUBLIC_PLAN_PRO_ID!,
name: 'Pro',
description: 'For professionals',
price: 29,
interval: 'month' as const,
popular: true,
features: [
'Unlimited projects',
'50 GB storage',
'Priority support',
'API access',
],
},
];
export const config = {
returnUrl: process.env.NEXT_PUBLIC_APP_URL + '/success',
portalReturnUrl: process.env.NEXT_PUBLIC_APP_URL + '/account',
};
Components use Tailwind CSS and shadcn/ui patterns. Customize via:
globals.cssExample - Custom colors:
/* globals.css */
@layer base {
:root {
--primary: 220 90% 56%;
--primary-foreground: 0 0% 100%;
}
}
Most components accept standard styling props:
<PricingTableOne
plans={plans}
onSelectPlan={handleSelect}
className="max-w-4xl mx-auto"
containerClassName="gap-8"
cardClassName="border-2"
/>
# .env.local
# Dodo Payments
DODO_PAYMENTS_API_KEY=sk_live_xxxxx
DODO_PAYMENTS_WEBHOOK_SECRET=whsec_xxxxx
# Product IDs (from dashboard)
NEXT_PUBLIC_PLAN_FREE_ID=prod_xxxxx
NEXT_PUBLIC_PLAN_PRO_ID=prod_xxxxx
NEXT_PUBLIC_PLAN_ENTERPRISE_ID=prod_xxxxx
# App
NEXT_PUBLIC_APP_URL=https://yoursite.com
Keep product IDs in environment variables for easy staging/production switching.
Components should show loading states during checkout:
const [loading, setLoading] = useState(false);
const handleSelect = async (planId: string) => {
setLoading(true);
try {
const response = await fetch('/api/checkout', {...});
const { checkoutUrl } = await response.json();
window.location.href = checkoutUrl;
} finally {
setLoading(false);
}
};
Fetch subscription data server-side when possible:
// app/account/page.tsx
import { getSubscription } from '@/lib/subscription';
export default async function AccountPage() {
const subscription = await getSubscription();
return <SubscriptionManagement subscription={subscription} />;
}
Always use webhooks as source of truth for subscription status, not client-side data.
Weekly Installs
139
Repository
GitHub Stars
7
First Seen
Jan 21, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
opencode114
gemini-cli112
codex106
github-copilot101
claude-code92
cursor86
Tailwind CSS v4 + shadcn/ui 生产级技术栈配置指南与最佳实践
2,600 周安装