stripe by claude-dev-suite/claude-dev-suite
npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill stripeimport Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
app.post('/api/checkout', async (req, res) => {
const session = await stripe.checkout.sessions.create({
mode: 'payment', // 或 'subscription'
line_items: [{ price: req.body.priceId, quantity: 1 }],
success_url: `${process.env.APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.APP_URL}/cancel`,
metadata: { userId: req.user.id },
});
res.json({ url: session.url });
});
// 服务端:创建意图
app.post('/api/payment-intent', async (req, res) => {
const intent = await stripe.paymentIntents.create({
amount: Math.round(req.body.amount * 100), // 单位:分
currency: 'usd',
automatic_payment_methods: { enabled: true },
metadata: { orderId: req.body.orderId },
}, { idempotencyKey: `order_${req.body.orderId}` });
res.json({ clientSecret: intent.client_secret });
});
// 客户端:React + Stripe.js
import { useStripe, useElements, PaymentElement } from '@stripe/react-stripe-js';
function CheckoutForm() {
const stripe = useStripe();
const elements = useElements();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const { error } = await stripe!.confirmPayment({
elements: elements!,
confirmParams: { return_url: `${window.location.origin}/success` },
});
if (error) setError(error.message!);
};
return (
<form onSubmit={handleSubmit}>
<PaymentElement />
<button disabled={!stripe}>支付</button>
</form>
);
}
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
app.post('/api/checkout', async (req, res) => {
const session = await stripe.checkout.sessions.create({
mode: 'payment', // or 'subscription'
line_items: [{ price: req.body.priceId, quantity: 1 }],
success_url: `${process.env.APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.APP_URL}/cancel`,
metadata: { userId: req.user.id },
});
res.json({ url: session.url });
});
// Server: create intent
app.post('/api/payment-intent', async (req, res) => {
const intent = await stripe.paymentIntents.create({
amount: Math.round(req.body.amount * 100), // cents
currency: 'usd',
automatic_payment_methods: { enabled: true },
metadata: { orderId: req.body.orderId },
}, { idempotencyKey: `order_${req.body.orderId}` });
res.json({ clientSecret: intent.client_secret });
});
// Client: React + Stripe.js
import { useStripe, useElements, PaymentElement } from '@stripe/react-stripe-js';
function CheckoutForm() {
const stripe = useStripe();
const elements = useElements();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const { error } = await stripe!.confirmPayment({
elements: elements!,
confirmParams: { return_url: `${window.location.origin}/success` },
});
if (error) setError(error.message!);
};
return (
<form onSubmit={handleSubmit}>
<PaymentElement />
<button disabled={!stripe}>Pay</button>
</form>
);
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
app.post('/api/subscribe', async (req, res) => {
const subscription = await stripe.subscriptions.create({
customer: customerId,
items: [{ price: req.body.priceId }],
payment_behavior: 'default_incomplete',
expand: ['latest_invoice.payment_intent'],
});
const invoice = subscription.latest_invoice as Stripe.Invoice;
const pi = invoice.payment_intent as Stripe.PaymentIntent;
res.json({ subscriptionId: subscription.id, clientSecret: pi.client_secret });
});
// 在周期结束时取消(非立即取消)
await stripe.subscriptions.update(subId, { cancel_at_period_end: true });
app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), (req, res) => {
const event = stripe.webhooks.constructEvent(
req.body, req.headers['stripe-signature']!, process.env.STRIPE_WEBHOOK_SECRET!
);
switch (event.type) {
case 'checkout.session.completed':
await fulfillOrder(event.data.object as Stripe.Checkout.Session);
break;
case 'invoice.paid':
await activateSubscription(event.data.object as Stripe.Invoice);
break;
case 'invoice.payment_failed':
await handleFailedPayment(event.data.object as Stripe.Invoice);
break;
case 'customer.subscription.deleted':
await deactivateSubscription(event.data.object as Stripe.Subscription);
break;
}
res.json({ received: true });
});
关键提示: 使用 express.raw() — 解析后的请求体会破坏签名验证。
| 反模式 | 修复方法 |
|---|---|
| 信任客户端金额 | 仅在服务端计算金额 |
| 无 Webhook 处理 | 始终使用 Webhook 进行履约 |
| 存储卡号 | 使用 Stripe.js — 绝不接触卡数据 |
| 无幂等性密钥 | 在所有创建操作中添加 |
| 支付确认前履约 | 等待 Webhook 确认 |
| 客户端无错误处理 | 显示来自 Stripe 的 error.message |
| 问题 | 修复方法 |
|---|---|
| Webhook 400 | 使用原始请求体,验证 STRIPE_WEBHOOK_SECRET |
| "价格不存在" | 检查测试/生产模式是否与 API 密钥匹配 |
| 重复扣款 | 添加幂等性密钥 |
| 重定向时出现 CORS | 确保所有地方都使用 HTTPS |
每周安装量
1
代码仓库
首次出现
3 天前
安全审计
安装于
amp1
cline1
openclaw1
opencode1
cursor1
kimi-cli1
app.post('/api/subscribe', async (req, res) => {
const subscription = await stripe.subscriptions.create({
customer: customerId,
items: [{ price: req.body.priceId }],
payment_behavior: 'default_incomplete',
expand: ['latest_invoice.payment_intent'],
});
const invoice = subscription.latest_invoice as Stripe.Invoice;
const pi = invoice.payment_intent as Stripe.PaymentIntent;
res.json({ subscriptionId: subscription.id, clientSecret: pi.client_secret });
});
// Cancel at period end (not immediately)
await stripe.subscriptions.update(subId, { cancel_at_period_end: true });
app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), (req, res) => {
const event = stripe.webhooks.constructEvent(
req.body, req.headers['stripe-signature']!, process.env.STRIPE_WEBHOOK_SECRET!
);
switch (event.type) {
case 'checkout.session.completed':
await fulfillOrder(event.data.object as Stripe.Checkout.Session);
break;
case 'invoice.paid':
await activateSubscription(event.data.object as Stripe.Invoice);
break;
case 'invoice.payment_failed':
await handleFailedPayment(event.data.object as Stripe.Invoice);
break;
case 'customer.subscription.deleted':
await deactivateSubscription(event.data.object as Stripe.Subscription);
break;
}
res.json({ received: true });
});
Critical: Use express.raw() — parsed body breaks signature verification.
| Anti-Pattern | Fix |
|---|---|
| Trust client-side amount | Calculate amount server-side only |
| No webhook handling | Always use webhooks for fulfillment |
| Storing card numbers | Use Stripe.js — never touch card data |
| No idempotency keys | Add to all create operations |
| Fulfilling before payment confirms | Wait for webhook confirmation |
| No error handling on client | Show error.message from Stripe |
| Issue | Fix |
|---|---|
| Webhook 400 | Use raw body, verify STRIPE_WEBHOOK_SECRET |
| "No such price" | Check test/live mode matches API key |
| Double charges | Add idempotency key |
| CORS on redirect | Ensure HTTPS everywhere |
Weekly Installs
1
Repository
First Seen
3 days ago
Security Audits
Installed on
amp1
cline1
openclaw1
opencode1
cursor1
kimi-cli1
Lark CLI IM 即时消息管理工具:机器人/用户身份操作聊天、消息、文件下载
20,000 周安装
Docnify自动化:通过Rube MCP和Composio工具包实现文档操作自动化
1 周安装
Docmosis自动化集成指南:通过Rube MCP与Composio实现文档生成自动化
1 周安装
Dictionary API自动化教程:通过Rube MCP和Composio实现词典API操作自动化
1 周安装
detrack-automation:自动化追踪技能,集成Claude AI提升开发效率
1 周安装
Demio自动化工具包:通过Rube MCP和Composio实现Demio操作自动化
1 周安装
Deel自动化工具:通过Rube MCP与Composio实现HR与薪资操作自动化
1 周安装