Production-ready Stripe integration for payments, subscriptions, and webhooks.
Payment Flows
| 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
| 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
| 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