mcpField
S
stripe-integration

stripe-integration

github.com/ovachiever开发5657 次安装48 周前更新
代码仓库

关于 stripe-integration

stripe-integration 是面向 Web 和移动应用开发者的 Stripe 支付集成 Skill,涵盖结账、订阅、客户管理、退款、Webhook 与支付测试。

主要功能

  1. 01实现托管结账和 Payment Intents
  2. 02设置定期订阅
  3. 03管理客户和支付方式
  4. 04处理并验证 Webhook
  5. 05处理退款并测试支付

适用场景

  1. 01为应用添加一次性结账
  2. 02构建订阅计费
  3. 03处理退款与争议
  4. 04通过 Webhook 处理支付事件

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ovachiever/droid-tings --skill stripe-integration

安装后在 Claude Code 中输入/stripe-integration确认已加载。

详细介绍

Stripe 集成

掌握 Stripe 支付处理集成,构建稳健且符合 PCI 要求的支付流程,包括结账、订阅、Webhook 和退款。

何时使用此技能

  • 在 Web/移动应用中实现支付处理
  • 设置订阅计费系统
  • 处理一次性付款和定期扣款
  • 处理退款和争议
  • 管理客户的支付方式
  • 为欧洲支付实现 SCA(强客户认证)
  • 使用 Stripe Connect 构建 marketplace 支付流程

核心概念

1. 支付流程

Checkout Session(托管式)

  • Stripe 托管的支付页面
  • PCI 合规负担极小
  • 实施速度最快
  • 支持一次性付款和定期付款

Payment Intents(自定义 UI)

  • 完全掌控支付 UI
  • 需使用 Stripe.js 以符合 PCI 要求
  • 实施较复杂
  • 自定义选项更多

Setup Intents(保存支付方式)

  • 收集支付方式,但不扣款
  • 用于订阅和未来付款
  • 需要客户确认
2. Webhook

关键事件:

  • payment_intent.succeeded:支付已完成
  • payment_intent.payment_failed:支付失败
  • customer.subscription.updated:订阅已变更
  • customer.subscription.deleted:订阅已取消
  • charge.refunded:退款已处理
  • invoice.payment_succeeded:订阅付款成功
3. 订阅

组成部分:

  • Product:您销售的商品或服务
  • Price:价格及计费频率
  • Subscription:客户的定期付款
  • Invoice:为每个计费周期生成的账单
4. 客户管理
  • 创建和管理客户记录
  • 保存多个支付方式
  • 跟踪客户元数据
  • 管理账单详情

快速开始

import stripe

stripe.api_key = "sk_test_..."

# Create a checkout session
session = stripe.checkout.Session.create(
    payment_method_types=['card'],
    line_items=[{
        'price_data': {
            'currency': 'usd',
            'product_data': {
                'name': 'Premium Subscription',
            },
            'unit_amount': 2000,  # $20.00
            'recurring': {
                'interval': 'month',
            },
        },
        'quantity': 1,
    }],
    mode='subscription',
    success_url='https://yourdomain.com/success?session_id={CHECKOUT_SESSION_ID}',
    cancel_url='https://yourdomain.com/cancel',
)

# Redirect user to session.url
print(session.url)

支付实现模式

模式 1:一次性付款(托管式结账)
def create_checkout_session(amount, currency='usd'):
    """Create a one-time payment checkout session."""
    try:
        session = stripe.checkout.Session.create(
            payment_method_types=['card'],
            line_items=[{
                'price_data': {
                    'currency': currency,
                    'product_data': {
                        'name': 'Purchase',
                        'images': ['https://example.com/product.jpg'],
                    },
                    'unit_amount': amount,  # Amount in cents
                },
                'quantity': 1,
            }],
            mode='payment',
            success_url='https://yourdomain.com/success?session_id={CHECKOUT_SESSION_ID}',
            cancel_url='https://yourdomain.com/cancel',
            metadata={
                'order_id': 'order_123',
                'user_id': 'user_456'
            }
        )
        return session
    except stripe.error.StripeError as e:
        # Handle error
        print(f"Stripe error: {e.user_message}")
        raise
模式 2:自定义 Payment Intent 流程
def create_payment_intent(amount, currency='usd', customer_id=None):
    """Create a payment intent for custom checkout UI."""
    intent = stripe.PaymentIntent.create(
        amount=amount,
        currency=currency,
        customer=customer_id,
        automatic_payment_methods={
            'enabled': True,
        },
        metadata={
            'integration_check': 'accept_a_payment'
        }
    )
    return intent.client_secret  # Send to frontend

# Frontend (JavaScript)
"""
const stripe = Stripe('pk_test_...');
const elements = stripe.elements();
const cardElement = elements.create('card');
cardElement.mount('#card-element');

const {error, paymentIntent} = await stripe.confirmCardPayment(
    clientSecret,
    {
        payment_method: {
            card: cardElement,
            billing_details: {
                name: 'Customer Name'
            }
        }
    }
);

if (error) {
    // Handle error
} else if (paymentIntent.status === 'succeeded') {
    // Payment successful
}
"""
模式 3:创建订阅
def create_subscription(customer_id, price_id):
    """Create a subscription for a customer."""
    try:
        subscription = stripe.Subscription.create(
            customer=customer_id,
            items=[{'price': price_id}],
            payment_behavior='default_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(f"Subscription creation failed: {e}")
        raise
模式 4:客户门户
def create_customer_portal_session(customer_id):
    """Create a portal session for customers to manage subscriptions."""
    session = stripe.billing_portal.Session.create(
        customer=customer_id,
        return_url='https://yourdomain.com/account',
    )
    return session.url  # Redirect customer here

Webhook 处理

安全的 Webhook 端点
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(f"Payment succeeded: {payment_intent['id']}")

def handle_failed_payment(payment_intent):
    """Handle failed payment."""
    error = payment_intent.get('last_payment_error', {})
    print(f"Payment 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(f"Subscription canceled: {subscription['id']}")
Webhook 最佳实践
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

客户管理

def create_customer(email, name, payment_method_id=None):
    """Create a Stripe customer."""
    customer = stripe.Customer.create(
        email=email,
        name=name,
        payment_method=payment_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,
        customer=customer_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(
        customer=customer_id,
        type='card'
    )
    return payment_methods.data

退款处理

def create_refund(payment_intent_id, amount=None, reason=None):
    """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'),
        }
    )

测试

# 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(
        email="[email protected]"
    )

    # Create payment intent
    intent = stripe.PaymentIntent.create(
        amount=1000,
        currency='usd',
        customer=customer.id,
        payment_method_types=['card']
    )

    # Confirm with test card
    confirmed = stripe.PaymentIntent.confirm(
        intent.id,
        payment_method='pm_card_visa'  # Test payment method
    )

    assert confirmed.status == 'succeeded'

资源

  • references/checkout-flows.md:详细的结账实现说明
  • references/webhook-handling.md:Webhook 安全与处理
  • references/subscription-management.md:订阅生命周期
  • references/customer-management.md:客户和支付方式管理
  • references/invoice-generation.md:发票生成与计费
  • assets/stripe-client.py:可用于生产环境的 Stripe 客户端封装
  • assets/webhook-handler.py:完整的 Webhook 处理器
  • assets/checkout-config.json:结账配置模板

最佳实践

  1. 始终使用 Webhook:不要只依赖客户端确认
  2. 幂等性:以幂等方式处理 Webhook 事件
  3. 错误处理:妥善处理所有 Stripe 错误
  4. 测试模式:上线前使用测试密钥进行充分测试
  5. 元数据:使用元数据将 Stripe 对象与您的数据库关联
  6. 监控:跟踪支付成功率和错误
  7. PCI 合规:切勿在服务器上处理原始银行卡数据
  8. 支持 SCA:为欧洲支付实现 3D Secure

常见问题

  • 未验证 Webhook:始终验证 Webhook 签名
  • 缺少 Webhook 事件:处理所有相关的 Webhook 事件
  • 金额硬编码:使用分/最小货币单位
  • 没有重试逻辑:为 API 调用实现重试机制
  • 忽略测试模式:使用测试卡测试所有边缘情况

评论

支持 Markdown