重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
stripe-stack by scientiacapital/skills
npx skills add https://github.com/scientiacapital/skills --skill stripe-stack<quick_start> 为 Next.js + Supabase 项目添加支付功能:
npm install stripe @stripe/stripe-jssetup-new-project.md 或 add-webhook-handler.md// Lazy-loaded Stripe client
import Stripe from 'stripe';
let _stripe: Stripe | null = null;
export function getStripe(): Stripe {
if (!_stripe) {
_stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: '2025-12-15.clover' });
}
return _stripe;
}
</quick_start>
<success_criteria> 集成成功的标准:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
<essential_principles>
幂等性不容妥协
测试/线上模式分离
sk_test_、pk_test_、whsec_test_sk_live_、pk_live_、whsec_live_共享 Stripe 账户
延迟客户端初始化
</essential_principles>
在继续之前,请明确你的用例:
| 用例 | 工作流程 | 描述 |
|---|---|---|
| 新项目 | setup-new-project.md | 从零开始的全新 Stripe 集成 |
| 添加 Webhooks | add-webhook-handler.md | 为现有项目添加 webhook 处理器 |
| 订阅 | implement-subscriptions.md | 带有套餐的周期性计费 |
| 积分系统 | add-credit-system.md | 按需付费积分 |
| 上线 | go-live-checklist.md | 测试 → 生产迁移 |
如果在新项目中设置 Stripe: → 阅读 workflows/setup-new-project.md → 然后阅读 reference/environment-vars.md → 使用 templates/stripe-client.ts 和 templates/env-example.txt
如果添加 webhook 处理: → 阅读 workflows/add-webhook-handler.md → 然后阅读 reference/webhook-patterns.md → 使用 templates/webhook-handler-nextjs.ts 和 templates/idempotency-migration.sql
如果实现订阅计费: → 阅读 workflows/implement-subscriptions.md → 然后阅读 reference/pricing-models.md → 使用 templates/plans-config.ts
如果添加积分/用量计费系统: → 阅读 workflows/add-credit-system.md → 然后阅读 reference/pricing-models.md
如果迁移测试 → 生产: → 阅读 workflows/go-live-checklist.md
<quick_reference>
# Server-side (never expose to client)
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
# Client-side (safe to expose)
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
# Optional: Price IDs (for test→live switching)
STRIPE_PRICE_STARTER_MONTHLY=price_...
STRIPE_PRICE_PRO_MONTHLY=price_...
| 事件 | 触发时机 | 操作 |
|---|---|---|
checkout.session.completed | 客户完成结账 | 创建订阅记录 |
customer.subscription.created | 新订阅开始 | 初始化用户限制 |
customer.subscription.updated | 套餐变更、续订 | 更新套餐/限制 |
customer.subscription.deleted | 取消订阅 | 降级到免费版 |
invoice.paid | 月度续订成功 | 重置用量计数器 |
invoice.payment_failed | 支付失败 | 标记为逾期 |
let _stripe: Stripe | null = null;
export function getStripe(): Stripe {
if (!_stripe) {
const key = process.env.STRIPE_SECRET_KEY;
if (!key) throw new Error('STRIPE_SECRET_KEY not configured');
_stripe = new Stripe(key, {
apiVersion: '2025-12-15.clover',
typescript: true
});
}
return _stripe;
}
CREATE TABLE stripe_webhook_events (
id TEXT PRIMARY KEY, -- Use Stripe event ID directly
type TEXT NOT NULL, -- Event type
data JSONB NOT NULL, -- Full event payload
processed_at TIMESTAMPTZ DEFAULT NOW()
);
export async function POST(request: NextRequest) {
const body = await request.text();
const signature = request.headers.get('stripe-signature');
// 1. Verify signature
const event = stripe.webhooks.constructEvent(body, signature, webhookSecret);
// 2. Check idempotency (BEFORE processing)
const { data: existing } = await supabase
.from('stripe_webhook_events')
.select('id')
.eq('id', event.id)
.single();
if (existing) return NextResponse.json({ duplicate: true });
// 3. Log event (INSERT before processing)
await supabase.from('stripe_webhook_events').insert({
id: event.id,
type: event.type,
data: event,
});
// 4. Process event
switch (event.type) {
case 'checkout.session.completed':
await handleCheckout(event.data.object);
break;
// ... other handlers
}
return NextResponse.json({ received: true });
}
</quick_reference>
<integration_notes>
request.text() 获取原始请求体supabase-sql-skill - 用于数据库迁移create-hooks-skill - 用于部署后通知私有模板和示例位于:github.com/ScientiaCapital/stripe-stack
</integration_notes>
<reference_index>
| 文件 | 用途 |
|---|---|
reference/webhook-patterns.md | 幂等性、事件处理、错误恢复 |
reference/pricing-models.md | 套餐 vs 积分 vs 用量计费 |
reference/environment-vars.md | 标准环境变量约定 |
reference/common-errors.md | 故障排除指南 |
| 文件 | 用途 |
|---|---|
templates/webhook-handler-nextjs.ts | 完整的 webhook 路由(可直接复制粘贴) |
templates/stripe-client.ts | 延迟加载的客户端工厂 |
templates/plans-config.ts | 订阅套餐定义 |
templates/idempotency-migration.sql | Supabase 迁移 |
templates/webhook-handler.test.ts | 测试模板 |
templates/env-example.txt | 标准 .env 模板 |
| 文件 | 用途 |
|---|---|
workflows/setup-new-project.md | 全新的 Stripe 集成 |
workflows/add-webhook-handler.md | 为现有项目添加 webhook |
workflows/implement-subscriptions.md | 订阅计费 |
workflows/add-credit-system.md | 按需付费积分 |
workflows/go-live-checklist.md | 测试 → 生产迁移 |
</reference_index>
作为最后一步,写入 ~/.claude/skill-analytics/last-outcome-stripe-stack.json:
{"ts":"[UTC ISO8601]","skill":"stripe-stack","version":"1.0.0","variant":"default",
"status":"[success|partial|error]","runtime_ms":[estimated ms from start],
"metrics":{"webhooks_configured":[n],"products_created":[n],"checkout_flows_built":[n]},
"error":null,"session_id":"[YYYY-MM-DD]"}
如果某些阶段失败但仍有结果产生,则使用状态 "partial"。仅当没有输出生成时才使用 "error"。
每周安装次数
45
仓库
GitHub 星标数
6
首次出现
2026年1月23日
安全审计
安装于
gemini-cli43
codex43
opencode42
claude-code40
github-copilot40
amp39
<quick_start> Add payments to a Next.js + Supabase project:
npm install stripe @stripe/stripe-jssetup-new-project.md or add-webhook-handler.md// Lazy-loaded Stripe client
import Stripe from 'stripe';
let _stripe: Stripe | null = null;
export function getStripe(): Stripe {
if (!_stripe) {
_stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: '2025-12-15.clover' });
}
return _stripe;
}
</quick_start>
<success_criteria> Integration is successful when:
<essential_principles>
Idempotency is Non-Negotiable
Test/Live Mode Separation
sk_test_, pk_test_, whsec_test_sk_live_, pk_live_, whsec_live_Shared Stripe Account
</essential_principles>
Before proceeding, identify your use case:
| Use Case | Workflow | Description |
|---|---|---|
| New project | setup-new-project.md | Fresh Stripe integration from scratch |
| Add webhooks | add-webhook-handler.md | Add webhook handler to existing project |
| Subscriptions | implement-subscriptions.md | Recurring billing with plans |
| Credit system | add-credit-system.md | Pay-as-you-go credits |
If setting up Stripe in a new project: → Read workflows/setup-new-project.md → Then read reference/environment-vars.md → Use templates/stripe-client.ts and templates/env-example.txt
If adding webhook handling: → Read workflows/add-webhook-handler.md → Then read reference/webhook-patterns.md → Use templates/webhook-handler-nextjs.ts and templates/idempotency-migration.sql
If implementing subscription billing: → Read workflows/implement-subscriptions.md → Then read reference/pricing-models.md → Use templates/plans-config.ts
If adding credit/usage-based system: → Read workflows/add-credit-system.md → Then read reference/pricing-models.md
If migrating test → production: → Read workflows/go-live-checklist.md
<quick_reference>
# Server-side (never expose to client)
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
# Client-side (safe to expose)
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
# Optional: Price IDs (for test→live switching)
STRIPE_PRICE_STARTER_MONTHLY=price_...
STRIPE_PRICE_PRO_MONTHLY=price_...
| Event | When It Fires | Action |
|---|---|---|
checkout.session.completed | Customer completes checkout | Create subscription record |
customer.subscription.created | New subscription starts | Initialize user limits |
customer.subscription.updated | Plan change, renewal | Update plan/limits |
customer.subscription.deleted | Cancellation | Downgrade to free |
invoice.paid |
let _stripe: Stripe | null = null;
export function getStripe(): Stripe {
if (!_stripe) {
const key = process.env.STRIPE_SECRET_KEY;
if (!key) throw new Error('STRIPE_SECRET_KEY not configured');
_stripe = new Stripe(key, {
apiVersion: '2025-12-15.clover',
typescript: true
});
}
return _stripe;
}
CREATE TABLE stripe_webhook_events (
id TEXT PRIMARY KEY, -- Use Stripe event ID directly
type TEXT NOT NULL, -- Event type
data JSONB NOT NULL, -- Full event payload
processed_at TIMESTAMPTZ DEFAULT NOW()
);
export async function POST(request: NextRequest) {
const body = await request.text();
const signature = request.headers.get('stripe-signature');
// 1. Verify signature
const event = stripe.webhooks.constructEvent(body, signature, webhookSecret);
// 2. Check idempotency (BEFORE processing)
const { data: existing } = await supabase
.from('stripe_webhook_events')
.select('id')
.eq('id', event.id)
.single();
if (existing) return NextResponse.json({ duplicate: true });
// 3. Log event (INSERT before processing)
await supabase.from('stripe_webhook_events').insert({
id: event.id,
type: event.type,
data: event,
});
// 4. Process event
switch (event.type) {
case 'checkout.session.completed':
await handleCheckout(event.data.object);
break;
// ... other handlers
}
return NextResponse.json({ received: true });
}
</quick_reference>
<integration_notes>
request.text() for raw bodysupabase-sql-skill - For database migrationscreate-hooks-skill - For post-deployment notificationsPrivate templates and examples available at: github.com/ScientiaCapital/stripe-stack
</integration_notes>
<reference_index>
| File | Purpose |
|---|---|
reference/webhook-patterns.md | Idempotency, event handling, error recovery |
reference/pricing-models.md | Plans vs Credits vs Usage-based billing |
reference/environment-vars.md | Standard env var conventions |
reference/common-errors.md | Troubleshooting guide |
| File | Purpose |
|---|---|
templates/webhook-handler-nextjs.ts | Complete webhook route (copy-paste) |
templates/stripe-client.ts | Lazy-loaded client factory |
templates/plans-config.ts | Subscription plan definitions |
templates/idempotency-migration.sql | Supabase migration |
templates/webhook-handler.test.ts | Test template |
templates/env-example.txt |
| File | Purpose |
|---|---|
workflows/setup-new-project.md | Fresh Stripe integration |
workflows/add-webhook-handler.md | Add webhook to existing project |
workflows/implement-subscriptions.md | Subscription billing |
workflows/add-credit-system.md | Pay-as-you-go credits |
workflows/go-live-checklist.md | Test → Production migration |
</reference_index>
As the final step, write to ~/.claude/skill-analytics/last-outcome-stripe-stack.json:
{"ts":"[UTC ISO8601]","skill":"stripe-stack","version":"1.0.0","variant":"default",
"status":"[success|partial|error]","runtime_ms":[estimated ms from start],
"metrics":{"webhooks_configured":[n],"products_created":[n],"checkout_flows_built":[n]},
"error":null,"session_id":"[YYYY-MM-DD]"}
Use status "partial" if some stages failed but results were produced. Use "error" only if no output was generated.
Weekly Installs
45
Repository
GitHub Stars
6
First Seen
Jan 23, 2026
Security Audits
Gen Agent Trust HubPassSocketWarnSnykWarn
Installed on
gemini-cli43
codex43
opencode42
claude-code40
github-copilot40
amp39
OKX CEX Earn CLI:OKX交易所赚币命令行工具,管理简单赚币、双币赢、链上赚币
1,700 周安装
Lazy Client Initialization
go-live-checklist.md |
| Test → Production migration |
| Monthly renewal success |
| Reset usage counters |
invoice.payment_failed | Payment failed | Mark as past_due |
| Standard .env template |