关于 stripe-integration
stripe-integration 是用于集成 Stripe 支付的开发技能,涵盖订阅和相关流程,并提供安全、Webhook、测试及客户生命周期管理指引。
主要功能
- 01支付与结账流程
- 02订阅计费模式
- 03Webhook 配置与事件处理
- 04安全与幂等性指引
- 05Stripe CLI 测试指引
适用场景
- 01为应用添加 Stripe 支付
- 02构建订阅计费
- 03配置并测试支付 Webhook
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ breverdbidder/ life-os --skill stripe-integration安装后在 Claude Code 中输入/stripe-integration确认已加载。
详细介绍
Stripe 集成
此技能可确保首次正确实现 Stripe 支付集成,并遵循安全性、可靠性和用户体验方面的最佳实践。
何时使用此技能
在以下情况下使用此技能:
- 将 Stripe 添加到新应用程序
- 实现订阅计费
- 设置支付处理
- 配置 Webhook
- 管理客户生命周期
- 处理退款或争议
- 实现结账流程
核心原则
安全第一:
- 绝不在客户端暴露密钥
- 生产环境始终使用 HTTPS
- 验证 Webhook 签名
- 使用 Stripe 的客户端库处理卡片信息
幂等性:
- 为 API 请求使用幂等键
- 处理重复的 Webhook 事件
- 确保设计可安全重试
用户体验:
- 清晰的错误消息
- 支付期间显示加载状态
- 提供成功/失败反馈
- 发送电子邮件确认
实现工作流
1. 环境设置
所需凭据:
STRIPE_PUBLISHABLE_KEY_TEST=pk_test_...
STRIPE_SECRET_KEY_TEST=sk_test_...
STRIPE_WEBHOOK_SECRET_TEST=whsec_...
STRIPE_PUBLISHABLE_KEY_PROD=pk_live_...
STRIPE_SECRET_KEY_PROD=sk_live_...
STRIPE_WEBHOOK_SECRET_PROD=whsec_...
切勿提交:
- 添加到 .env 或密钥管理器
- 使用 .gitignore 忽略环境文件
- 为开发/预发布/生产环境使用不同的密钥
安装:
# Node.js
npm install stripe @stripe/stripe-js
# Python
pip install stripe
2. 基本支付流程
客户端(React 示例):
import { loadStripe } from '@stripe/stripe-js';
import { Elements, CardElement, useStripe, useElements } from '@stripe/react-stripe-js';
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY);
function CheckoutForm() {
const stripe = useStripe();
const elements = useElements();
const handleSubmit = async (event) => {
event.preventDefault();
if (!stripe || !elements) return;
// Create payment intent on backend first
const { clientSecret } = await fetch('/api/create-payment-intent', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ amount: 5000 }) // $50.00
}).then(r => r.json());
// Confirm payment on client
const { error, paymentIntent } = await stripe.confirmCardPayment(
clientSecret,
{
payment_method: {
card: elements.getElement(CardElement),
billing_details: {
name: 'Customer Name',
email: '[email protected]'
}
}
}
);
if (error) {
console.error(error.message);
} else if (paymentIntent.status === 'succeeded') {
// Payment successful
console.log('Payment succeeded!');
}
};
return (
<form onSubmit={handleSubmit}>
<CardElement />
<button type="submit" disabled={!stripe}>
Pay
</button>
</form>
);
}
服务端(Node.js 示例):
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
app.post('/api/create-payment-intent', async (req, res) => {
try {
const { amount } = req.body;
const paymentIntent = await stripe.paymentIntents.create({
amount: amount,
currency: 'usd',
automatic_payment_methods: {
enabled: true,
},
metadata: {
userId: req.user.id, // Track in your DB
orderId: req.body.orderId
}
});
res.json({ clientSecret: paymentIntent.client_secret });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
3. 订阅实现
创建订阅:
// Server-side
async function createSubscription(customerId, priceId) {
const subscription = await stripe.subscriptions.create({
customer: customerId,
items: [{ price: priceId }],
payment_behavior: 'default_incomplete',
payment_settings: {
save_default_payment_method: 'on_subscription'
},
expand: ['latest_invoice.payment_intent']
});
return {
subscriptionId: subscription.id,
clientSecret: subscription.latest_invoice.payment_intent.client_secret
};
}
处理订阅生命周期:
- 客户注册 → 创建客户和订阅
- 支付成功 → 启用功能
- 支付失败 → 通知客户并重试
- 收到取消请求 → 在 period_end 处理
- 续订 → Webhook 确认支付
4. Webhook 配置
重要:Webhook 是 Stripe 通知你事件的方式,必须正确实现。
端点设置:
const express = require('express');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
app.post('/webhook', express.raw({type: 'application/json'}), async (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
// Verify webhook signature
event = stripe.webhooks.constructEvent(
req.body,
sig,
process.env.STRIPE_WEBHOOK_SECRET
);
} catch (err) {
console.log(`Webhook signature verification failed: ${err.message}`);
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// Handle the event
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object;
await handlePaymentSuccess(paymentIntent);
break;
case 'payment_intent.payment_failed':
const failedPayment = event.data.object;
await handlePaymentFailure(failedPayment);
break;
case 'customer.subscription.created':
const subscription = event.data.object;
await handleSubscriptionCreated(subscription);
break;
case 'customer.subscription.updated':
const updatedSub = event.data.object;
await handleSubscriptionUpdated(updatedSub);
break;
case 'customer.subscription.deleted':
const deletedSub = event.data.object;
await handleSubscriptionCanceled(deletedSub);
break;
case 'invoice.payment_succeeded':
const invoice = event.data.object;
await handleInvoicePaymentSucceeded(invoice);
break;
case 'invoice.payment_failed':
const failedInvoice = event.data.object;
await handleInvoicePaymentFailed(failedInvoice);
break;
default:
console.log(`Unhandled event type ${event.type}`);
}
res.json({received: true});
});
需要处理的重要事件:
payment_intent.succeeded- 一次性支付成功payment_intent.payment_failed- 支付失败customer.subscription.created- 新订阅customer.subscription.updated- 订阅已更改customer.subscription.deleted- 订阅已取消invoice.payment_succeeded- 定期支付成功invoice.payment_failed- 定期支付失败
5. 客户管理
创建客户:
const customer = await stripe.customers.create({
email: user.email,
name: user.name,
metadata: {
userId: user.id
}
});
// Store customer.id in your database
await db.users.update(user.id, {
stripeCustomerId: customer.id
});
关联支付方式:
const paymentMethod = await stripe.paymentMethods.attach(
pm_id,
{ customer: customerId }
);
await stripe.customers.update(customerId, {
invoice_settings: {
default_payment_method: pm_id
}
});
6. 测试
测试模式:
- 使用测试密钥(pk_test_、sk_test_)
- 测试卡号:
- 成功:
4242 4242 4242 4242 - 被拒:
4000 0000 0000 0002 - 3D Secure:
4000 0027 6000 3184
- 成功:
- 使用 stripe CLI 测试 Webhook:
stripe listen --forward-to localhost:3000/webhook stripe trigger payment_intent.succeeded
Webhook 测试:
# Install Stripe CLI
brew install stripe/stripe-cli/stripe
# Login
stripe login
# Forward webhooks to local server
stripe listen --forward-to localhost:3000/webhook
# Trigger events manually
stripe trigger customer.subscription.created
7. 错误处理
需要处理的常见错误:
try {
const charge = await stripe.charges.create({...});
} catch (error) {
switch (error.type) {
case 'StripeCardError':
// Card was declined
console.log('Card declined:', error.message);
break;
case 'StripeInvalidRequestError':
// Invalid parameters
console.log('Invalid request:', error.message);
break;
case 'StripeAPIError':
// Stripe API error
console.log('API error:', error.message);
break;
case 'StripeConnectionError':
// Network error
console.log('Network error');
break;
case 'StripeAuthenticationError':
// Authentication error
console.log('Auth error');
break;
default:
console.log('Unknown error:', error);
}
}
生产环境检查清单
上线前:
- 使用正式 API 密钥(pk_live_、sk_live_)
- 所有位置均已启用 HTTPS
- 已在 Stripe Dashboard 中配置 Webhook 端点
- 已实现 Webhook 签名验证
- 已处理所有关键事件
- API 调用均使用幂等键
- 客户创建与用户账户关联
- 已为所有支付流程处理错误
- 已设置电子邮件通知
- 已记录退款流程
- 已使用真实测试卡进行测试
- 已通过 CLI 测试 Webhook 事件
- 已测试订阅续订流程
- 已测试取消流程
- 已实现支付失败重试逻辑
- 已完成安全审查
常见模式
订阅层级
const plans = {
basic: 'price_basic123',
pro: 'price_pro456',
enterprise: 'price_enterprise789'
};
function subscribeToPlan(customerId, tier) {
return stripe.subscriptions.create({
customer: customerId,
items: [{ price: plans[tier] }]
});
}
按用量计费
// Record usage
await stripe.subscriptionItems.createUsageRecord(
subscriptionItemId,
{
quantity: 100,
timestamp: Math.floor(Date.now() / 1000),
action: 'increment'
}
);
按比例计算升级费用
await stripe.subscriptions.update(subscriptionId, {
items: [{
id: subscriptionItemId,
price: newPriceId
}],
proration_behavior: 'create_prorations'
});
资源
官方文档:
- https://stripe.com/docs
- https://stripe.com/docs/webhooks
- https://stripe.com/docs/billing/subscriptions/overview
测试:
安全:
提示
- 从简单功能开始:先确保基本支付功能正常,再实现订阅
- 使用 Stripe Checkout:托管页面可处理复杂流程
- 彻底测试 Webhook:使用 CLI 模拟所有事件
- 记录所有信息:在数据库中跟踪支付意向和事件
- 妥善处理故障:实现重试逻辑并通知用户
- 隔离测试和生产环境:切勿混用密钥或环境
- 监控 Stripe Dashboard:检查错误和争议
- 阅读 Stripe 文档:内容出色且详尽
评论
支持 Markdown