Back to Payments & Billing

stripe-integration

Stripepaymentse-commercesubscriptionswebhooksPCI compliancecheckoutbilling
36.8k📄 MIT🕒 2026-06-16Source ↗

Install this skill

npx skills add wshobson/agents

Works across Claude Code, Cursor, Codex, Copilot & Antigravity

This skill facilitates the integration of Stripe payment architecture into software projects. It supports the implementation of hosted Checkout sessions for rapid deployment, custom Payment Intents for tailored user interfaces, and Setup Intents for recurring billing management. The integration logic covers backend coordination with Stripe's API to ensure secure transaction handling, including metadata mapping and error processing. It assists in maintaining PCI compliance by managing the offloading of sensitive card data to Stripe's managed components. Developers can automate lifecycle events through webhooks, ensuring the backend state remains synchronized with payment, subscription status, and refund activities. The skill provides structured patterns for connecting user records to payment profiles, streamlining the transition from initial customer acquisition to sustained revenue collection.

When to Use This Skill

  • Launching a SaaS platform requiring recurring monthly subscription billing
  • Adding an e-commerce checkout flow to a custom web application
  • Building a marketplace payment split system using Stripe Connect
  • Managing customer payment method updates and renewal failures
  • Processing partial or full refunds triggered by user support tickets

How to Invoke This Skill

Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:

  • integrate Stripe checkout into my app
  • how to handle subscription billing with Stripe
  • setup Stripe webhook endpoints for payment confirmation
  • create a payment intent for custom checkout flow
  • how do I save a customer card for future payments

Pro Tips

  • 💡Always rely on webhooks for critical payment lifecycle events (e.g., `payment_intent.succeeded`) rather than solely client-side callbacks, to ensure data integrity and prevent fraud.
  • 💡Implement comprehensive error handling and logging for all Stripe API interactions and webhook endpoints to quickly diagnose and resolve any payment processing issues.
  • 💡Regularly review Stripe's API documentation and security best practices, particularly regarding PCI compliance and Strong Customer Authentication (SCA), to keep your integration up-to-date and secure.

What this skill does

  • Implementation of hosted Stripe Checkout for one-time and subscription payments
  • Development of custom Payment Intent flows using Stripe.js for UI control
  • Webhook listener configuration for event-driven backend updates
  • Customer and subscription resource lifecycle management
  • Setup Intent handling for secure off-session payment method storage

When not to use it

  • Applications requiring non-Stripe payment gateways or direct crypto-currency settlement
  • Scenarios where internal, non-compliant storage of raw credit card numbers is mandatory
  • Offline-only applications lacking server-side communication capabilities

Example workflow

  1. Define product pricing and subscription intervals in the Stripe dashboard
  2. Initialize the backend to accept requests for new checkout sessions
  3. Route the user to the returned Stripe-hosted URL
  4. Configure a webhook endpoint to receive and verify payment success events
  5. Update local database records once the payment status is confirmed as succeeded

Prerequisites

  • Stripe account with API keys configured
  • Server environment capable of processing HTTP requests
  • HTTPS-enabled domain for webhook delivery

Pitfalls & limitations

  • !Failure to verify webhook signatures can expose endpoints to spoofing attacks
  • !Assuming all payments are successful without handling partial payment or manual review statuses
  • !Hardcoding prices instead of using Stripe Price IDs leads to maintenance overhead
  • !Neglecting to account for currency conversion or rounding differences when dealing with cents

FAQ

Should I use Checkout or Payment Intents?
Use Checkout if you want the fastest, lowest-maintenance integration that handles compliance automatically. Use Payment Intents if your design requires a deeply customized checkout flow within your own UI.
What happens if my server is down during a payment?
Stripe will retry failed webhook deliveries for up to three days. Ensure your endpoint is idempotent so it can safely process the same event multiple times if needed.
How do I handle European payments?
Stripe manages Strong Customer Authentication (SCA) automatically within the Checkout and Payment Element flows, ensuring compliance with local regulations.

How it compares

Generic prompts often fail to handle the stateful nature of Stripe webhooks or secure secret rotation; this skill enforces established patterns that prevent common synchronization bugs and security leaks.

Source & trust

37k stars📄 MIT🕒 Updated 2026-06-16
📄 Full skill instructions — original source: wshobson/agents
# 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 Session (Hosted)**

- Stripe-hosted payment page
- Minimal PCI compliance burden
- Fastest implementation
- Supports one-time and recurring payments

**Payment Intents (Custom UI)**

- Full control over payment UI
- Requires Stripe.js for PCI compliance
- More complex implementation
- Better customization options

**Setup Intents (Save Payment Methods)**

- Collect payment method without charging
- Used for subscriptions and future payments
- Requires customer confirmation

### 2. 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

### 3. Subscriptions

**Components:**

- **Product**: What you're selling
- **Price**: How much and how often
- **Subscription**: Customer's recurring payment
- **Invoice**: Generated for each billing cycle

### 4. 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(
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)


## 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(
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


### Pattern 2: Custom Payment Intent Flow

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
}
"""


### Pattern 3: 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 4: 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="[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'


## Resources

- **references/checkout-flows.md**: Detailed checkout implementation
- **references/webhook-handling.md**: Webhook security and processing
- **references/subscription-management.md**: Subscription lifecycle
- **references/customer-management.md**: Customer and payment method handling
- **references/invoice-generation.md**: Invoicing and billing
- **assets/stripe-client.py**: Production-ready Stripe client wrapper
- **assets/webhook-handler.py**: Complete webhook processor
- **assets/checkout-config.json**: Checkout configuration templates

## Best Practices

1. **Always Use Webhooks**: Don't rely solely on client-side confirmation
2. **Idempotency**: Handle webhook events idempotently
3. **Error Handling**: Gracefully handle all Stripe errors
4. **Test Mode**: Thoroughly test with test keys before production
5. **Metadata**: Use metadata to link Stripe objects to your database
6. **Monitoring**: Track payment success rates and errors
7. **PCI Compliance**: Never handle raw card data on your server
8. **SCA Ready**: Implement 3D Secure for European payments

## Common Pitfalls

- **Not Verifying Webhooks**: Always verify webhook signatures
- **Missing Webhook Events**: Handle all relevant webhook events
- **Hardcoded Amounts**: Use cents/smallest currency unit
- **No Retry Logic**: Implement retries for API calls
- **Ignoring Test Mode**: Test all edge cases with test cards

How to Use This Skill Unit

Option A: Project-Specific (Recommended)

  1. Click "Download" above
  2. In your project, create the directory: .agent/skills/stripe-integration/
  3. Save the file as SKILL.md
  4. The agent will automatically discover the skill based on its description.

Option B: Global Installation (All Agents)

Save the file to these locations to make it available across all projects:

  • Claude Code: ~/.claude/skills/wshobson/agents/stripe-integration/SKILL.md
  • Cursor: ~/.cursor/skills/wshobson/agents/stripe-integration/SKILL.md
  • Antigravity: ~/.gemini/antigravity/skills/wshobson/agents/stripe-integration/SKILL.md

🚀 Install with CLI:
npx skills add wshobson/agents

Read the Master Guide: Mastering Agent Skills

Recommended Rules

View more rules

Recommended Workflows

View more workflows

Recommended MCP Servers

View more MCP servers

Take It Further

Maximize your productivity with these powerful resources

📋

Define Your Standards

Set up coding standards to ensure this workflow produces consistent, high-quality results.

Browse Rules Library
📖

Master Workflows

Learn how to create custom workflows, use Turbo Mode, and build your automation library.

Complete Guide

How to use this Skill in Claude Code & Cursor

For Claude Code (CLI)

To use this skill in Claude Code, copy the rule content into your project's custom instructions or follow our Add-Skill CLI guide. This ensures Claude follows your standards during every code generation.

For Cursor & Windsurf

For Cursor or Windsurf, individual skills are best used in the "Rules for AI" section. This specific unit helps the agent avoid payments & billing issues, leading to cleaner, more efficient code.

Why the skill format matters: the standardized Agent Skills format lets your AI agent load detailed instructions only when they are relevant, keeping your prompt clean while improving results.

Source & attribution

This skill is categorized under Payments & Billing and is published by W. Shobson, maintained in wshobson/agents.

← Browse All Agent Skills
Sponsored AI assistant. Recommendations may be paid.