Django Stripe Subscriptions: How To Guide
By Andrew on 9/27/2024
This guide will walk you through implementing Stripe subscriptions using a Django backend (with dj-stripe) and a React frontend. We’ll cover setting up the backend API, creating React components for subscription management, and handling the communication between the two.
If you just want an out of the box, production-ready solution to do stripe subscriptions, authentication, and much more, check out our starter kit: slimsaas kit.
Table of Contents
- Prerequisites
- Backend Setup
- Frontend Setup
- API Endpoints
- React Components
- Stripe Elements Integration
- Handling Subscriptions
- Webhook Handling
- Testing
- Best Practices
Prerequisites
- Django project with dj-stripe set up (refer to the previous guide)
- React project set up (you can use Create React App)
- Stripe account and API keys
Backend Setup
-
Install necessary packages:
pip install djangorestframework django-cors-headers
-
Update
settings.py
:INSTALLED_APPS = [ # ... 'rest_framework', 'corsheaders', ] MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', # ... other middleware ] CORS_ALLOWED_ORIGINS = [ "http://localhost:3000", # Your React app's address ]
-
Create serializers for your subscription data:
# serializers.py from rest_framework import serializers from djstripe.models import Product, Price, Subscription class ProductSerializer(serializers.ModelSerializer): class Meta: model = Product fields = ['id', 'name', 'description'] class PriceSerializer(serializers.ModelSerializer): class Meta: model = Price fields = ['id', 'unit_amount', 'currency', 'recurring'] class SubscriptionSerializer(serializers.ModelSerializer): class Meta: model = Subscription fields = ['id', 'status', 'current_period_end']
Frontend Setup
-
Install necessary packages:
npm install @stripe/stripe-js @stripe/react-stripe-js axios
-
Set up Stripe in your React app:
// src/stripe.js import { loadStripe } from '@stripe/stripe-js'; const stripePromise = loadStripe('your_publishable_key'); export default stripePromise;
API Endpoints
Create views and URLs for your subscription API:
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from djstripe.models import Product, Price, Subscription
from .serializers import ProductSerializer, PriceSerializer, SubscriptionSerializer
class ProductListView(APIView):
def get(self, request):
products = Product.objects.filter(active=True)
serializer = ProductSerializer(products, many=True)
return Response(serializer.data)
class CreateSubscriptionView(APIView):
def post(self, request):
# Implementation for creating a subscription
pass
# urls.py
from django.urls import path
from .views import ProductListView, CreateSubscriptionView
urlpatterns = [
path('products/', ProductListView.as_view()),
path('create-subscription/', CreateSubscriptionView.as_view()),
]
React Components
Create components for displaying and managing subscriptions:
// src/components/ProductList.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
const ProductList = () => {
const [products, setProducts] = useState([]);
useEffect(() => {
const fetchProducts = async () => {
const response = await axios.get('http://localhost:8000/api/products/');
setProducts(response.data);
};
fetchProducts();
}, []);
return (
<div>
<h2>Available Subscriptions</h2>
{products.map(product => (
<div key={product.id}>
<h3>{product.name}</h3>
<p>{product.description}</p>
{/* Add subscription button here */}
</div>
))}
</div>
);
};
export default ProductList;
Stripe Elements Integration
Integrate Stripe Elements for secure payment collection:
// src/components/CheckoutForm.js
import React from 'react';
import { CardElement, useStripe, useElements } from '@stripe/react-stripe-js';
const CheckoutForm = ({ priceId }) => {
const stripe = useStripe();
const elements = useElements();
const handleSubmit = async (event) => {
event.preventDefault();
if (!stripe || !elements) {
return;
}
const result = await stripe.createPaymentMethod({
type: 'card',
card: elements.getElement(CardElement),
});
if (result.error) {
console.log(result.error.message);
} else {
// Send paymentMethod.id to your server
const response = await axios.post('http://localhost:8000/api/create-subscription/', {
payment_method_id: result.paymentMethod.id,
price_id: priceId,
});
// Handle the response
}
};
return (
<form onSubmit={handleSubmit}>
<CardElement />
<button type="submit" disabled={!stripe}>Subscribe</button>
</form>
);
};
export default CheckoutForm;
Handling Subscriptions
On the backend, handle the subscription creation:
# views.py
import stripe
from django.conf import settings
from rest_framework.views import APIView
from rest_framework.response import Response
from djstripe.models import Customer
stripe.api_key = settings.STRIPE_SECRET_KEY
class CreateSubscriptionView(APIView):
def post(self, request):
try:
# Get the Stripe Customer
customer = Customer.objects.get(subscriber=request.user)
# Create the subscription
subscription = stripe.Subscription.create(
customer=customer.id,
items=[{'price': request.data['price_id']}],
payment_behavior='default_incomplete',
expand=['latest_invoice.payment_intent'],
)
return Response({
'subscriptionId': subscription.id,
'clientSecret': subscription.latest_invoice.payment_intent.client_secret
})
except Exception as e:
return Response({'error': str(e)}, status=400)
Webhook Handling
Ensure your webhook handling (as set up with dj-stripe) is working correctly to process subscription events.
Testing
- Test the entire flow from selecting a product to completing a subscription
- Use Stripe’s test cards to simulate various scenarios
- Verify that subscription status is correctly updated in both Stripe and your database
Best Practices
- Always use HTTPS in production
- Implement proper error handling and user feedback
- Use Stripe’s test mode during development
- Keep your Stripe API keys and webhook secrets secure
- Regularly update your dependencies (React, Stripe libraries, dj-stripe)
- Implement logging for easier debugging
- Consider implementing a user dashboard for subscription management
This guide provides a foundation for integrating React with Django and Stripe for subscription handling. Remember to consult the official documentation for React, Django, dj-stripe, and Stripe for the most up-to-date information and best practices.
If your interested in a more comprehensive, production ready solution that solves for all the headaches setting up stripe, authentication, and much more, check out the slimsaas kit
Get SlimSaaS!