Stripe 是全球最流行的在线支付平台,支持信用卡、借记卡、Apple Pay、Google Pay 等多种支付方式。Stripe 以开发者友好著称,API 设计优雅、文档完善,是 SaaS 产品收款的首选。
为什么选择 Stripe#
| 特性 | 说明 |
|---|---|
| 全球支付 | 支持 135+ 种货币,195+ 个国家 |
| 多种支付方式 | 信用卡、Apple Pay、SEPA 等 |
| 订阅管理 | 内置订阅计费系统 |
| 开发者友好 | 优秀的 SDK 和文档 |
| 安全合规 | PCI DSS Level 1 认证 |
注册与配置#
1. 注册 Stripe#
- 访问 stripe.com
- 创建账户(需要非大陆地区银行账户收款)
- 完成业务认证
2. 获取 API 密钥#
Dashboard → Developers → API keys
Publishable key: pk_test_xxx(客户端使用)Secret key: sk_test_xxx(服务端使用)注意:测试环境使用 test 密钥,生产环境使用 live 密钥。
3. 安装 SDK#
# Node.jsnpm install stripe
# React 组件npm install @stripe/stripe-js @stripe/react-stripe-jsCheckout 集成#
Checkout 是 Stripe 托管的支付页面,最快捷的集成方式。
服务端创建会话#
import Stripe from 'stripe'
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)
export async function POST(req: Request) { const { priceId } = await req.json()
const session = await stripe.checkout.sessions.create({ mode: 'payment', // 或 'subscription' payment_method_types: ['card'], line_items: [ { price: priceId, quantity: 1, }, ], success_url: `${process.env.NEXT_PUBLIC_URL}/success?session_id={CHECKOUT_SESSION_ID}`, cancel_url: `${process.env.NEXT_PUBLIC_URL}/cancel`, })
return Response.json({ url: session.url })}客户端跳转#
async function handleCheckout() { const response = await fetch('/api/checkout', { method: 'POST', body: JSON.stringify({ priceId: 'price_xxx' }), }) const { url } = await response.json() window.location.href = url}支付成功页面#
import Stripe from 'stripe'
export default async function SuccessPage({ searchParams }) { const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)
const session = await stripe.checkout.sessions.retrieve( searchParams.session_id )
return ( <div> <h1>支付成功!</h1> <p>订单号:{session.id}</p> </div> )}订阅支付#
创建产品和价格#
Dashboard → Products → Add product
或通过 API:
// 创建产品const product = await stripe.products.create({ name: 'Pro Plan', description: '专业版订阅',})
// 创建价格const price = await stripe.prices.create({ product: product.id, unit_amount: 1999, // 分为单位,即 $19.99 currency: 'usd', recurring: { interval: 'month' },})订阅 Checkout#
const session = await stripe.checkout.sessions.create({ mode: 'subscription', line_items: [ { price: 'price_xxx', quantity: 1, }, ], success_url: '...', cancel_url: '...',})管理订阅#
// 获取订阅const subscription = await stripe.subscriptions.retrieve('sub_xxx')
// 取消订阅await stripe.subscriptions.cancel('sub_xxx')
// 更新订阅await stripe.subscriptions.update('sub_xxx', { items: [{ price: 'price_new' }],})Customer Portal#
让用户自助管理订阅:
const session = await stripe.billingPortal.sessions.create({ customer: 'cus_xxx', return_url: `${process.env.NEXT_PUBLIC_URL}/account`,})
// 跳转到 session.urlWebhook 处理#
Webhook 用于接收支付事件通知,实现业务逻辑。
配置 Webhook#
Dashboard → Developers → Webhooks → Add endpoint
Endpoint URL: https://your-domain.com/api/webhookEvents: checkout.session.completed, customer.subscription.updated, ...处理事件#
import Stripe from 'stripe'
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)
export async function POST(req: Request) { const body = await req.text() const sig = req.headers.get('stripe-signature')!
let event: Stripe.Event
try { event = stripe.webhooks.constructEvent( body, sig, process.env.STRIPE_WEBHOOK_SECRET! ) } catch (err) { return new Response('Webhook Error', { status: 400 }) }
switch (event.type) { case 'checkout.session.completed': const session = event.data.object as Stripe.Checkout.Session // 处理支付成功 await handlePaymentSuccess(session) break
case 'customer.subscription.updated': const subscription = event.data.object as Stripe.Subscription // 处理订阅更新 await handleSubscriptionUpdate(subscription) break
case 'customer.subscription.deleted': // 处理订阅取消 break }
return new Response('OK')}常用事件#
| 事件 | 触发时机 |
|---|---|
| checkout.session.completed | Checkout 支付成功 |
| invoice.paid | 发票支付成功 |
| invoice.payment_failed | 支付失败 |
| customer.subscription.created | 新建订阅 |
| customer.subscription.updated | 订阅更新 |
| customer.subscription.deleted | 订阅取消 |
嵌入式支付表单#
使用 Stripe Elements 在页面内嵌入支付表单。
设置 Elements#
'use client'
import { loadStripe } from '@stripe/stripe-js'import { Elements, PaymentElement, 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 (e: React.FormEvent) => { e.preventDefault()
if (!stripe || !elements) return
const { error } = await stripe.confirmPayment({ elements, confirmParams: { return_url: `${window.location.origin}/success`, }, })
if (error) { console.error(error.message) } }
return ( <form onSubmit={handleSubmit}> <PaymentElement /> <button type="submit" disabled={!stripe}> 支付 </button> </form> )}
export default function Checkout({ clientSecret }: { clientSecret: string }) { return ( <Elements stripe={stripePromise} options={{ clientSecret }}> <CheckoutForm /> </Elements> )}创建 PaymentIntent#
export async function POST(req: Request) { const { amount } = await req.json()
const paymentIntent = await stripe.paymentIntents.create({ amount, currency: 'usd', })
return Response.json({ clientSecret: paymentIntent.client_secret })}测试支付#
测试卡号#
| 卡号 | 场景 |
|---|---|
| 4242 4242 4242 4242 | 成功支付 |
| 4000 0000 0000 9995 | 余额不足 |
| 4000 0000 0000 0002 | 卡被拒绝 |
有效期:任意未来日期 CVC:任意 3 位数字
Stripe CLI#
# 安装brew install stripe/stripe-cli/stripe
# 登录stripe login
# 监听 Webhook(本地开发)stripe listen --forward-to localhost:3000/api/webhook
# 触发测试事件stripe trigger checkout.session.completed最佳实践#
1. 使用幂等键#
防止重复扣款:
const paymentIntent = await stripe.paymentIntents.create( { amount: 1000, currency: 'usd' }, { idempotencyKey: `order_${orderId}` })2. 保存客户信息#
// 创建客户const customer = await stripe.customers.create({ email: 'user@example.com', metadata: { userId: 'user_123' },})
// 关联到 Checkoutconst session = await stripe.checkout.sessions.create({ customer: customer.id, // ...})3. 处理 Webhook 签名#
始终验证 Webhook 签名,防止伪造请求。
4. 错误处理#
try { const paymentIntent = await stripe.paymentIntents.create(...)} catch (error) { if (error instanceof Stripe.errors.StripeCardError) { // 卡错误 } else if (error instanceof Stripe.errors.StripeInvalidRequestError) { // 请求错误 }}常见问题#
国内能用 Stripe 吗?#
Stripe 不支持大陆主体直接注册。解决方案:
- 使用香港/美国公司主体
- 使用 Paddle、LemonSqueezy 等替代
- 使用国内支付(支付宝、微信支付)
如何处理退款?#
const refund = await stripe.refunds.create({ payment_intent: 'pi_xxx', amount: 1000, // 部分退款})多货币支持#
const session = await stripe.checkout.sessions.create({ currency: 'eur', // 欧元 // ...})