ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Stripe 支付集成实战指南:Checkout Sessions、订阅计费与 Webhook 安全处理(agents24 stripe-integration 技能解析)

Stripe 支付集成实战指南:Checkout Sessions、订阅计费与 Webhook 安全处理(agents24 stripe-integration 技能解析) Stripe 支付集成实战指南Checkout Sessions、订阅计费与 Webhook 安全处理agents24 stripe-integration 技能解析【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents导读本文基于 agents24 仓库中 stripe-integration 技能 及其 详细模式文档系统讲解 Stripe 支付集成的完整技术路径从 Checkout Sessions 与 Payment Intents 的选择到订阅计费、客户支付方式管理、Webhook 签名校验与幂等处理再到退款、争议与测试。读完本文你将掌握一套可直接落地的 PCI 合规支付接入方案能够独立完成 Web/移动应用的一次性支付、订阅计费与自动化账单处理。技能定位与适用场景stripe-integration是支付处理插件plugins/payment-processing中的核心技能用于实现健壮、PCI 合规的支付流程覆盖结账checkout、订阅subscription与 Webhook 三个关键领域。该技能尤其适用于以下场景在 Web/移动应用中实现支付处理搭建订阅计费系统处理一次性支付与周期性扣款处理退款refund与争议dispute管理客户支付方式面向欧洲市场的 SCAStrong Customer Authentication强客户认证合规支付基于 Stripe Connect 构建市场/平台型支付流。从技能定义frontmatter看其 description 明确要求在集成 Stripe 支付、构建订阅系统或实现安全结账流时使用与同目录下的 payment-integration Agent统筹 Stripe/PayPal/Square 集成和 pci-compliance 技能PCI DSS 合规形成互补——前者负责策略统筹后者负责安全底线。核心概念一三种支付流的选型Stripe 集成中最容易出错的就是选错 API 抽象层。该技能明确将支付流划分为三种1. Checkout Sessions推荐用于大多数集成Checkout Sessions 是 Stripe 官方推荐的首选方案因为它在服务端一次调用即可生成一个完整的结账会话并内置了大量开箱即用的能力支持全部 UI 形态Stripe 托管结账页hosted checkout、嵌入式结账表单embedded checkout、以及基于 Elements 的自定义 UI使用ui_modecustom配合 Payment Element、Express Checkout Element内置结账能力line items商品行、折扣discounts、税费tax、运费shipping、地址收集address collection、保存支付方式saved payment methods以及完整的结账生命周期事件相比 Payment Intents 的集成与长期维护成本更低——支付方式的多样性、SCA 等合规细节由 Stripe 托管处理。2. Payment Intents定制化控制当你的业务需要完全掌控结账体验时使用 Payment Intents但其代价是你需要自行计算最终金额包括税费、折扣、订阅价格与货币转换实现复杂度与长期维护负担显著高于 Checkout Sessions由于需要在自建页面上收集卡信息必须依赖 Stripe.jsElements才能满足 PCI 合规——原始卡号绝不允许经过你的服务器。3. Setup Intents保存支付方式不扣款用于在不发起扣款的前提下收集并保存客户的支付方式典型场景是创建订阅前的支付方式绑定为未来的后付费pay later场景做准备。与 Payment Intents 的关键区别在于 Setup Intents 只保存支付授权不产生交易金额且需要客户确认confirmation后才算完成设置。核心概念二Webhook 关键事件支付是典型的异步流程扣款成功、订阅变更等结果通过 Webhook 推送到你的服务端。技能列出以下必须监听的关键事件事件类型语义payment_intent.succeeded支付完成payment_intent.payment_failed支付失败customer.subscription.updated订阅变更如价格调整、周期变化customer.subscription.deleted订阅被取消charge.refunded退款处理完成invoice.payment_succeeded订阅账单支付成功周期性收款成功后续的Webhook 安全处理小节将给出这些事件的完整落地方案。核心概念三订阅模型与客户管理订阅的四层对象模型技能用四个对象概括 Stripe 订阅计费的领域模型Product产品你出售的东西抽象的商品或服务定义Price价格卖多少钱、多久收一次如 20 美元/月Subscription订阅客户与你的周期性付款约定Invoice发票每个计费周期自动生成一次。这四层与 billing-automation 技能 描述的账单生命周期trial → active → past_due → canceled / paused / resumed协同工作Stripe 负责按周期出账与扣款应用侧只需围绕invoice.payment_succeeded等事件做业务响应。客户管理四要素创建并管理客户记录stripe.Customer为客户保存多个支付方式跟踪客户 metadata自定义元数据如内部 user_id管理账单细节billing details。快速上手一条命令创建订阅结账会话技能提供的 Quick Start 是理解 Stripe 集成的最短路径——只需一个stripe.checkout.Session.create调用即可获得一个可重定向的托管结账地址import stripe stripe.api_key sk_test_... # Create a checkout session session stripe.checkout.Session.create( line_items[{ price_data: { currency: usd, product_data: { name: Premium Subscription, }, unit_amount: 2000, # $20.00单位美分 recurring: { interval: month, }, }, quantity: 1, }], modesubscription, success_urlhttps://yourdomain.com/success?session_id{CHECKOUT_SESSION_ID}, cancel_urlhttps://yourdomain.com/cancel ) # 将用户重定向到 session.url print(session.url)要点说明modesubscription与price_data.recurring组合声明这是一个周期性订阅若仅需一次性支付将mode改为payment并去掉recurring即可unit_amount的单位是最小货币单位美分2000即 $20.00success_url/cancel_url中的{CHECKOUT_SESSION_ID}是 Stripe 自动替换的模板占位符用于回跳后在服务端查询会话状态stripe.api_key必须使用测试密钥sk_test_...详见文末测试章节。五大实操模式来自 references/details.md技能主文档把深度内容收敛在 references/details.md 中以下五个模式是其中最核心的实战模板可直接复制改造。模式一一次性支付托管结账适用于最简单的商品售卖场景把mode设为payment并可通过metadata携带业务侧的订单与用户标识def create_checkout_session(amount, currencyusd): Create a one-time payment checkout session. try: session stripe.checkout.Session.create( line_items[{ price_data: { currency: currency, product_data: { name: Blue T-shirt, images: [https://example.com/product.jpg], }, unit_amount: amount, # Amount in cents }, quantity: 1, }], modepayment, success_urlhttps://yourdomain.com/success?session_id{CHECKOUT_SESSION_ID}, cancel_urlhttps://yourdomain.com/cancel, metadata{ order_id: order_123, user_id: user_456 } ) return session except stripe.error.StripeError as e: # Handle error print(fStripe error: {e.user_message}) raise注意stripe.error.StripeError异常基类与e.user_message面向用户的友好错误信息的使用这是生产级代码的基本错误处理姿势。模式二Elements Checkout Sessions自定义 UI当你想把结账页嵌入自己的站点而非跳转到 Stripe 托管页时使用ui_modecustom创建会话服务端只返回client_secret给前端def create_checkout_session_for_elements(amount, currencyusd): Create a checkout session configured for Payment Element. session stripe.checkout.Session.create( modepayment, ui_modecustom, line_items[{ price_data: { currency: currency, product_data: {name: Blue T-shirt}, unit_amount: amount, }, quantity: 1, }], return_urlhttps://yourdomain.com/complete?session_id{CHECKOUT_SESSION_ID} ) return session.client_secret # Send to frontend前端使用stripe.initCheckout接管整个结账流程加载动作、挂载 Payment Element、更新邮箱、触发确认const stripe Stripe(pk_test_...); const appearance { theme: stripe }; const checkout stripe.initCheckout({ clientSecret, elementsOptions: { appearance }, }); const loadActionsResult await checkout.loadActions(); if (loadActionsResult.type success) { const { actions } loadActionsResult; const session actions.getSession(); const button document.getElementById(pay-button); const checkoutContainer document.getElementById(checkout-container); const emailInput document.getElementById(email); const emailErrors document.getElementById(email-errors); const errors document.getElementById(confirm-errors); // Display a formatted string representing the total amount checkoutContainer.append(Total: ${session.total.total.amount}); // Mount Payment Element const paymentElement checkout.createPaymentElement(); paymentElement.mount(#payment-element); // Store email for submission emailInput.addEventListener(blur, () { actions.updateEmail(emailInput.value).then((result) { if (result.error) emailErrors.textContent result.error.message; }); }); // Handle form submission button.addEventListener(click, () { actions.confirm().then((result) { if (result.type error) errors.textContent result.error.message; }); }); }关键点前端拿到的是client_secret与公开密钥pk_test_...卡号等敏感数据由 Stripe 的 iframe 收集你的服务器与前端 JS 全程不接触原始卡号——这正是 PCI 合规的核心前提。模式三Elements Payment Intents自建结账 UI 的替代方案官方推荐优先采用模式二但当你需要完全自定义结账页时可以用 Payment Intents 替代。服务端创建 Payment Intent 并返回client_secretdef create_payment_intent(amount, currencyusd, customer_idNone): Create a payment intent for bespoke checkout UI with Payment Element. intent stripe.PaymentIntent.create( amountamount, currencycurrency, customercustomer_id, automatic_payment_methods{ enabled: True, }, metadata{ integration_check: accept_a_payment } ) return intent.client_secret # Send to frontend前端通过stripe.confirmPayment完成确认// Mount Payment Element and confirm via Payment Intents const stripe Stripe(pk_test_...); const appearance { theme: stripe }; const elements stripe.elements({ appearance, clientSecret }); const paymentElement elements.create(payment); paymentElement.mount(#payment-element); document.getElementById(pay-button).addEventListener(click, async () { const { error } await stripe.confirmPayment({ elements, confirmParams: { return_url: https://yourdomain.com/complete, }, }); if (error) { document.getElementById(errors).textContent error.message; } });automatic_payment_methods.enabledTrue意味着 Stripe 会根据客户地区自动提供合适的支付方式并处理 SCA 认证显著降低合规实现成本。模式四创建订阅含首期付款确认订阅创建与一次性支付的关键差异在于payment_behavior与expand参数前者控制首期付款失败时的行为后者让你在一次往返中拿到首张发票对应的 Payment Intent以便直接向客户发起付款确认def create_subscription(customer_id, price_id): Create a subscription for a customer. try: subscription stripe.Subscription.create( customercustomer_id, items[{price: price_id}], payment_behaviordefault_incomplete, payment_settings{save_default_payment_method: on_subscription}, expand[latest_invoice.payment_intent], ) return { subscription_id: subscription.id, client_secret: subscription.latest_invoice.payment_intent.client_secret } except stripe.error.StripeError as e: print(fSubscription creation failed: {e}) raisepayment_behaviordefault_incomplete订阅以incomplete状态创建直到首期付款成功后才转为activepayment_settings.save_default_payment_methodon_subscription将本次使用的支付方式自动保存为默认支付方式后续周期扣款无需客户重复授权返回的client_secret用于前端完成首期付款的 3D Secure / SCA 认证。模式五客户自助门户Billing Portal为减少客服成本Stripe 提供托管客户门户让客户自助管理订阅与支付方式。服务端只需一次调用并重定向def create_customer_portal_session(customer_id): Create a portal session for customers to manage subscriptions. session stripe.billing_portal.Session.create( customercustomer_id, return_urlhttps://yourdomain.com/account, ) return session.url # Redirect customer here客户可以在门户中完成升级/降级套餐、更换支付方式、查看发票、取消订阅等操作而这些动作产生的customer.subscription.updated/deleted事件会通过 Webhook 同步回你的系统。Webhook 安全处理签名校验与幂等支付事件异步到达安全性是 Webhook 端点设计的头等大事。技能给出了完整的 Flask 实现范式from flask import Flask, request import stripe app Flask(__name__) endpoint_secret whsec_... app.route(/webhook, methods[POST]) def webhook(): payload request.data sig_header request.headers.get(Stripe-Signature) try: event stripe.Webhook.construct_event( payload, sig_header, endpoint_secret ) except ValueError: # Invalid payload return Invalid payload, 400 except stripe.error.SignatureVerificationError: # Invalid signature return Invalid signature, 400 # Handle the event if event[type] payment_intent.succeeded: payment_intent event[data][object] handle_successful_payment(payment_intent) elif event[type] payment_intent.payment_failed: payment_intent event[data][object] handle_failed_payment(payment_intent) elif event[type] customer.subscription.deleted: subscription event[data][object] handle_subscription_canceled(subscription) return Success, 200 def handle_successful_payment(payment_intent): Process successful payment. customer_id payment_intent.get(customer) amount payment_intent[amount] metadata payment_intent.get(metadata, {}) # Update your database # Send confirmation email # Fulfill order print(fPayment succeeded: {payment_intent[id]}) def handle_failed_payment(payment_intent): Handle failed payment. error payment_intent.get(last_payment_error, {}) print(fPayment failed: {error.get(message)}) # Notify customer # Update order status def handle_subscription_canceled(subscription): Handle subscription cancellation. customer_id subscription[customer] # Update user access # Send cancellation email print(fSubscription canceled: {subscription[id]})这一范式与 payment-integration Agent 中Critical Requirements章节的要求完全吻合归纳为五条硬性约束签名校验不可省略必须使用官方 SDK如stripe.Webhook.construct_event验证Stripe-Signature头。ValueError表示 payload 非法SignatureVerificationError表示签名不匹配均须返回 400。跳过签名校验等同于向恶意请求敞开系统大门保留原始请求体验签基于原始字节任何 JSON 中间件对 body 的改写都会破坏签名验证——这正是示例中使用request.data而非request.get_json()的原因幂等处理Webhook 失败会重试且 Stripe 不保证单次投递。必须把event.id存入数据库处理前先查重快速响应应在200ms 内返回2xx把数据库写入、外部 API 调用等耗时操作放到响应之后异步执行否则超时触发重试会导致重复处理服务端二次确认支付状态以服务端向 Stripe API 重新查询的结果为准不要轻信 Webhook payload 或前端返回值。Webhook 签名的手动验证与幂等封装若无法使用 SDK或想深入理解原理技能也提供了 HMAC-SHA256 的手动验证实现与幂等包装器import hashlib import hmac def verify_webhook_signature(payload, signature, secret): Manually verify webhook signature. expected_sig hmac.new( secret.encode(utf-8), payload, hashlib.sha256 ).hexdigest() return hmac.compare_digest(signature, expected_sig) def handle_webhook_idempotently(event_id, handler): Ensure webhook is processed exactly once. # Check if event already processed if is_event_processed(event_id): return # Process event try: handler() mark_event_processed(event_id) except Exception as e: log_error(e) # Stripe will retry failed webhooks raise注意hmac.compare_digest的使用——它执行常量时间比较可防御时序攻击。幂等包装器的核心思想是先查重、再处理、成功后标记、失败则抛出异常以触发 Stripe 重试。客户与支付方式管理围绕stripe.Customer与stripe.PaymentMethod的完整生命周期管理def create_customer(email, name, payment_method_idNone): Create a Stripe customer. customer stripe.Customer.create( emailemail, namename, payment_methodpayment_method_id, invoice_settings{ default_payment_method: payment_method_id } if payment_method_id else None, metadata{ user_id: 12345 } ) return customer def attach_payment_method(customer_id, payment_method_id): Attach a payment method to a customer. stripe.PaymentMethod.attach( payment_method_id, customercustomer_id ) # Set as default stripe.Customer.modify( customer_id, invoice_settings{ default_payment_method: payment_method_id } ) def list_customer_payment_methods(customer_id): List all payment methods for a customer. payment_methods stripe.PaymentMethod.list( customercustomer_id, typecard ) return payment_methods.data三个动作对应三类场景create_customer注册即建档若客户在注册时已提供支付方式 token可同时将其设为默认支付方式attach_payment_method客户在账户设置中新增/更换卡时先attach再通过Customer.modify提升为默认支付方式list_customer_payment_methods在结账页或账户页展示已保存的卡仅返回 token 化的支付方式对象绝不包含完整卡号。退款与争议处理退款支持全额与部分退款并可附加退款原因争议dispute/拒付则以证据提交为处理手段def create_refund(payment_intent_id, amountNone, reasonNone): Create a refund. refund_params { payment_intent: payment_intent_id } if amount: refund_params[amount] amount # Partial refund if reason: refund_params[reason] reason # duplicate, fraudulent, requested_by_customer refund stripe.Refund.create(**refund_params) return refund def handle_dispute(charge_id, evidence): Update dispute with evidence. stripe.Dispute.modify( charge_id, evidence{ customer_name: evidence.get(customer_name), customer_email_address: evidence.get(customer_email), shipping_documentation: evidence.get(shipping_proof), customer_communication: evidence.get(communication), } )不传amount即为全额退款传入amount则执行部分退款reason的合法取值包括duplicate重复收费、fraudulent欺诈与requested_by_customer客户要求争议处理的关键是在 Stripe 规定的时限内提交证据客户姓名/邮箱、物流凭证、客服沟通记录证据的质量直接决定拒付仲裁结果。退款的最终结果通过charge.refundedWebhook 事件回传。测试测试密钥、测试卡与全流程验证技能强调所有开发工作都应基于测试模式test mode并给出了完整的测试卡矩阵与全流程测试代码# Use test mode keys stripe.api_key sk_test_... # Test card numbers TEST_CARDS { success: 4242424242424242, declined: 4000000000000002, 3d_secure: 4000002500003155, insufficient_funds: 4000000000009995 } def test_payment_flow(): Test complete payment flow. # Create test customer customer stripe.Customer.create( emailtestexample.com ) # Create payment intent intent stripe.PaymentIntent.create( amount1000, automatic_payment_methods{ enabled: True }, currencyusd, customercustomer.id ) # Confirm with test card confirmed stripe.PaymentIntent.confirm( intent.id, payment_methodpm_card_visa # Test payment method ) assert confirmed.status succeeded测试卡矩阵语义测试卡号场景4242424242424242支付成功4000000000000002支付被拒绝4000002500003155需要 3D Secure 认证4000000000009995余额不足测试要点stripe.PaymentIntent.confirm支持直接传入 Stripe 预置的测试支付方式 token如pm_card_visa无需真实卡号即可触发完整扣款链路用pm_card_visa配合assert confirmed.status succeeded验证主流程换用4000000000000002等卡号即可回归失败路径测试模式与生产模式必须严格隔离。payment-integration Agent 特别警告误配置导致生产环境接受测试卡是真实的 PCI 违规事故——Test credentials must fail in production。PCI 合规要点为什么不该碰原始卡号Stripe 技能反复强调PCI 合规并非口号而是有具体的架构约束。结合 pci-compliance 技能 的 12 项 PCI DSS 核心要求本技能落地为三条可直接执行的原则绝不处理原始卡数据卡号、CVV 必须由 Stripe.js / Elements / Stripe 托管页在 Stripe 的 iframe 内收集并 token 化。你的服务器永远不要存储、传输或记录完整卡号。pci-compliance 技能中给出了日志脱敏示例PAN 掩码保留前 6 后 4 位中间打码以及禁止存储清单磁道数据、CVV、PIN 属于永远禁止项服务端校验所有支付验证必须在服务端通过直连 Stripe API 完成而不是信任前端返回结果环境隔离测试密钥在生产环境必须失效。更进一步pci-compliance 技能 还提供了两类兜底方案供确实需要接触卡数据的团队参考一是服务端仅接触 tokencharge_with_token、store_payment_method二是高级自定义 token vault基于secrets.token_urlsafe生成随机 token配合 Fernet 对称加密存储卡数据映射以及在传输层强制 TLS 1.2、会话 Cookie 安全属性Secure/HttpOnly/SameSite等加固手段。与同插件其他技能的协作边界stripe-integration并非孤立存在它与 plugins/payment-processing 下的其他技能形成完整体系billing-automation在订阅模型之上补充计费周期、dunning欠费催缴重试、proration按比例计费、税务计算等自动化能力pci-compliance提供 PCI DSS 合规清单、数据最小化与 tokenization/加密实现paypal-integration多支付通道场景下与 Stripe 并行使用payment-integration Agent作为策略层统筹以上技能的选用时机并沉淀了 Webhook 安全、幂等、快速响应等跨通道通用要求。结语从技能到生产可用的接入路径回顾整个技能体系一条清晰的落地路径是先用 Checkout Sessions 以最小成本跑通一次性支付与订阅结账当需要自定义 UI 时升级到ui_modecustom的 Elements 方案用 Setup Intents 完成先绑卡、后扣款场景围绕六大 Webhook 事件搭建带签名校验与幂等处理的事件处理层最后用测试卡矩阵覆盖成功、拒绝、3D Secure、余额不足四类路径再在充分验证后切换生产密钥。全程守住服务器不碰原始卡号这条 PCI 红线即完成了一套健壮、合规、可维护的 Stripe 支付接入。延伸阅读仓库内路径stripe-integration 技能主文档stripe-integration 详细模式文档pci-compliance 技能PCI DSS 与 tokenizationbilling-automation 技能订阅生命周期与 dunningpayment-integration Agent支付集成策略与安全要求【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进