stripe-payments
SKILL.md
Stripe Payment Integration
Production-ready Stripe integration for payments, subscriptions, and webhooks.
Payment Flows
| Flow | Use Case | PCI Burden |
|---|---|---|
| Checkout Session | Hosted page, fastest setup | Minimal |
| Payment Intents | Custom UI, full control | Requires Stripe.js |
| Setup Intents | Save card for later | Minimal |
Quick Start - Checkout Session
import stripe
stripe.api_key = "sk_test_..."
session = stripe.checkout.Session.create(
payment_method_types=['card'],
line_items=[{
'price_data': {
'currency': 'usd',
'product_data': {'name': 'Premium Plan'},
'unit_amount': 2000, # $20.00 in cents
'recurring': {'interval': 'month'},
},
'quantity': 1,
}],
mode='subscription',
success_url='https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url='https://example.com/cancel',
)
# Redirect to session.url
Custom Payment Intent Flow
# Backend: Create payment intent
def create_payment_intent(amount, customer_id=None):
intent = stripe.PaymentIntent.create(
amount=amount, # In cents
currency='usd',
customer=customer_id,
automatic_payment_methods={'enabled': True},
)
return intent.client_secret
// Frontend: Confirm payment
const stripe = Stripe('pk_test_...');
const {error, paymentIntent} = await stripe.confirmCardPayment(
clientSecret,
{payment_method: {card: cardElement}}
);
Webhook Handling
@app.route('/webhook', methods=['POST'])
def webhook():
payload = request.data
sig = request.headers.get('Stripe-Signature')
try:
event = stripe.Webhook.construct_event(
payload, sig, 'whsec_...'
)
except stripe.error.SignatureVerificationError:
return 'Invalid signature', 400
if event['type'] == 'payment_intent.succeeded':
handle_payment_success(event['data']['object'])
elif event['type'] == 'customer.subscription.deleted':
handle_subscription_canceled(event['data']['object'])
return 'OK', 200
Critical Webhook Events
| Event | When to Handle |
|---|---|
payment_intent.succeeded |
Payment completed |
payment_intent.payment_failed |
Payment failed |
customer.subscription.updated |
Subscription changed |
customer.subscription.deleted |
Subscription canceled |
invoice.payment_succeeded |
Subscription payment OK |
Subscription Management
# Create subscription
subscription = stripe.Subscription.create(
customer=customer_id,
items=[{'price': 'price_xxx'}],
payment_behavior='default_incomplete',
expand=['latest_invoice.payment_intent'],
)
# Customer portal for self-service
session = stripe.billing_portal.Session.create(
customer=customer_id,
return_url='https://example.com/account',
)
# Redirect to session.url
Refunds
# Full refund
stripe.Refund.create(payment_intent='pi_xxx')
# Partial refund
stripe.Refund.create(
payment_intent='pi_xxx',
amount=500, # $5.00
reason='requested_by_customer'
)
Test Cards
| Card Number | Result |
|---|---|
4242424242424242 |
Success |
4000000000000002 |
Declined |
4000002500003155 |
3D Secure required |
4000000000009995 |
Insufficient funds |
Best Practices
- Always use webhooks - Don't rely on client-side confirmation
- Idempotency - Handle webhook events exactly once
- Metadata - Link Stripe objects to your database
- Test mode - Test all flows before production
- PCI compliance - Never handle raw card data server-side
- SCA - Implement 3D Secure for European payments
Common Pitfalls
- Not verifying webhook signatures
- Hardcoding amounts (use cents!)
- Missing webhook event handlers
- No retry logic for API calls
- Skipping test card scenarios
Weekly Installs
84
Repository
eyadsibai/ltkFirst Seen
Jan 28, 2026
Security Audits
Installed on
gemini-cli72
opencode72
codex69
github-copilot68
claude-code66
cursor64