Integrating Flutterwave Payment Gateway into Django: A Step-by-Step Guide
For Django web applications looking to streamline online payments, Flutterwave offers a versatile payment gateway solution. This step-by-step guide will walk you through the process of integrating Flutterwave into your Django application.
Before we delve into the integration process, let's consider why Flutterwave might be the ideal choice for your Django project. Key factors to assess include ease of use, supported payment methods, security features, and comprehensive documentation.
Step 1: Create a Flutterwave Account
Begin by signing up for a Flutterwave account. Head over to the official flutterwave website and follow the straightforward registration process.
https://www.flutterwave.com/
Step 2: Obtain API Keys
Upon creating your account, navigate to the Flutterwave dashboard to retrieve your API keys and other essential credentials. These keys will be pivotal for authenticating requests from your Django application. These keys are;
1. Public Key
2. Secret Key
Step 3: Packages
You might want to install packages such as:
pip install cryptography
pip install pycryptodome
Step 4: Create models
Depending on your project requirements, you might need to expand or modify your models accordingly.
But find an example below;
class Payment(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
email = models.EmailField()
first_name = models.CharField(max_length=20, blank=True, null=True)
total_amount = models.DecimalField(max_digits=10, decimal_places=2)
reference = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
status = models.CharField(max_length=20, default='pending')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
Step 5: Setup Views
Depending on your project requirements, you might need to expand or modify your views accordingly but following this pattern.
from rest_framework.views import APIView
from rest_framework.response import Response
import requests
from rest_framework.permissions import IsAuthenticated
class InitiatePayment(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
total_amount = request.data.get('total_amount') # Change to POST for form data(if you are using templates) or request.data.get for JSON
email = request.data.get('email')
reference = str(uuid.uuid4())
user = request.user
if user.is_anonymous:
return Response({'error': 'User is not authenticated'}, status=400)
# Replace these with your actual Flutterwave details
flutterwave_url = "https://api.flutterwave.com/v3/payments"
secret_key = "FLUTTERWAVE_SECRET_KEY" #"your_flutterwave_secret_key_here"
payload = {
"tx_ref": reference,
"amount": total_amount,
"currency": "NGN",
"redirect_url": "http://127.0.0.1:8000/payment/callback",#(Note this url must be hosted) # Replace with your callback URL
"payment_type": "card",
"customer": {
"email": email
}
}
headers = {
"Authorization": f"Bearer {django_secret_key}",
"Content-Type": "application/json"
}
try:
payment = Payment(user=user, amount=total_amount, reference=reference, status="pending")
payment.save()
response = requests.post(flutterwave_url, json=payload, headers=headers)
response_data = response.json()
return Response(response_data, status=status.HTTP_200_OK)
except requests.exceptions.RequestException as err:
# Handle request exceptions
return JsonResponse({'error': 'Payment initiation failed'}, status=500)
except ValueError as err:
# Handle JSON decoding error
return JsonResponse({'error': 'Payment initiation failed'}, status=500)
class PaymentCallback(APIView):
def get(self, request):
status = request.GET.get('status')
tx_ref = request.GET.get('tx_ref')
if status == 'successful':
try:
payment = Payment.objects.get(reference=tx_ref)
payment.status = "successful"
payment.save()
cart_items = Cart.objects.filter(user=payment.user, payment__isnull=True)
payment.items.set(cart_items.values_list('items', flat=True))
# Create an order with payment information
order = Order.objects.create(
user=payment.user,
total_cost=payment.amount,
payment=payment
)
# Add the items related to the payment to the order
order.items.set(cart_items.values_list('items', flat=True))
cart_items.update(payment=payment)
return Response({'message': 'Payment was successful'})
except Payment.DoesNotExist:
return Response({'error': 'Payment not found'}, status=status.HTTP_404_NOT_FOUND)
return Response({'error': 'Payment failed'})
Step 6: Setup Serializer
Depending on your project requirements setup for your model. You can use this;
class PaymentSerializer(serializers.ModelSerializer):
class Meta:
model = Payment
fields = '__all__'
Step 7: Setup Urls
Depending on your project requirements setup for your model, so the initiate-payment url redirects to flutterwave web application where the payment transaction is done. After payment is successful it redirects to the payment-callback endpoint. You can use this;
from django.urls import path
from . import views
from django.views.decorators.csrf import csrf_exempt
urlpatterns = [
path('initiate-payment/', csrf_exempt(views.InitiatePayment.as_view()), name='initiate_payment'),
path('payment/callback/', views.PaymentCallback.as_view(), name='payment_callback'),
]
Step 8: Settings Configurations
Configure flutterwave payment gateway in to your django settings.
Find the structure below:
FLUTTERWAVE_PUBLIC_KEY = 'FLUTTERWAVE_PUBLIC_KEY'
FLUTTERWAVE_SECRET_KEY = 'FLUTTERWAVE_PUBLIC_KEY'
So far, this are all you need to integrate the flutterwave payment gateway successfully.
When you test the endpoint, you should see something like this below:
{ "status": "success",
"message": "Hosted Link",
"data": {
"link": "https://ravemodal-
dev.herokuapp.com/v3/hosted/pay/4426840j3nbf08f8e" } }
So depending on your response in the views determine, your response during testing and beyond.
I hope this helps.
Interested in giving feedback or having any issues or confusion?
Reach me via
twitter: Joel Inyang
linkedIn: Joel Inyang
Subscribe to my newsletter
Read articles from Joel Inyang directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by