stripe-integration

Master Stripe payment processing integration for robust, PCI-compliant payment flows including checkout, subscriptions, webhooks, and refunds.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "stripe-integration" with this command: npx skills add wshobson/agents/wshobson-agents-stripe-integration

Stripe Integration

Master Stripe payment processing integration for robust, PCI-compliant payment flows including checkout, subscriptions, webhooks, and refunds.

When to Use This Skill

  • Implementing payment processing in web/mobile applications

  • Setting up subscription billing systems

  • Handling one-time payments and recurring charges

  • Processing refunds and disputes

  • Managing customer payment methods

  • Implementing SCA (Strong Customer Authentication) for European payments

  • Building marketplace payment flows with Stripe Connect

Core Concepts

  1. Payment Flows

Checkout Sessions

  • Recommended for most integrations

  • Supports all UI paths:

  • Stripe-hosted checkout page

  • Embedded checkout form

  • Custom UI with Elements (Payment Element, Express Checkout Element) using ui_mode='custom'

  • Provides built-in checkout capabilities (line items, discounts, tax, shipping, address collection, saved payment methods, and checkout lifecycle events)

  • Lower integration and maintenance burden than Payment Intents

Payment Intents (Bespoke control)

  • You calculate the final amount with taxes, discounts, subscriptions, and currency conversion yourself.

  • More complex implementation and long-term maintenance burden

  • Requires Stripe.js for PCI compliance

Setup Intents (Save Payment Methods)

  • Collect payment method without charging

  • Used for subscriptions and future payments

  • Requires customer confirmation

  1. Webhooks

Critical Events:

  • payment_intent.succeeded : Payment completed

  • payment_intent.payment_failed : Payment failed

  • customer.subscription.updated : Subscription changed

  • customer.subscription.deleted : Subscription canceled

  • charge.refunded : Refund processed

  • invoice.payment_succeeded : Subscription payment successful

  1. Subscriptions

Components:

  • Product: What you're selling

  • Price: How much and how often

  • Subscription: Customer's recurring payment

  • Invoice: Generated for each billing cycle

  1. Customer Management
  • Create and manage customer records

  • Store multiple payment methods

  • Track customer metadata

  • Manage billing details

Quick Start

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, }], 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)

Payment Implementation Patterns

Pattern 1: One-Time Payment (Hosted Checkout)

def create_checkout_session(amount, currency='usd'): """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, }], 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

Pattern 2: Elements with Checkout Sessions

def create_checkout_session_for_elements(amount, currency='usd'): """Create a checkout session configured for Payment Element.""" session = stripe.checkout.Session.create( mode='payment', ui_mode='custom', line_items=[{ 'price_data': { 'currency': currency, 'product_data': {'name': 'Blue T-shirt'}, 'unit_amount': amount, }, 'quantity': 1, }], return_url='https://yourdomain.com/complete?session_id={CHECKOUT_SESSION_ID}' ) return session.client_secret # Send to frontend

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; }); }); }

Pattern 3: Elements with Payment Intents

Pattern 2 (Elements with Checkout Sessions) is Stripe's recommended approach, but you can also use Payment Intents as an alternative.

def create_payment_intent(amount, currency='usd', customer_id=None): """Create a payment intent for bespoke checkout UI with Payment Element.""" 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

// 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; } });

Pattern 4: Subscription Creation

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

Pattern 5: Customer Portal

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 Handling

Secure Webhook Endpoint

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 Best Practices

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

Customer Management

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

Refund Handling

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'), } )

Testing

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="test@example.com" )

# Create payment intent
intent = stripe.PaymentIntent.create(
    amount=1000,
    automatic_payment_methods={
        'enabled': True
    },
    currency='usd',
    customer=customer.id
)

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

assert confirmed.status == 'succeeded'

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

tailwind-design-system

Tailwind Design System (v4)

Repository Source
19.1K31.3Kwshobson
Automation

api-design-principles

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

nodejs-backend-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

nextjs-app-router-patterns

No summary provided by upstream source.

Repository SourceNeeds Review