McTaba Labs logo
Software EngineeringThe WhiteboardProjectsEventsMasterclassesWebinarsLearn
Book Call

500+ developers already in the community

Get answers, find accountability partners, and stay ahead

Join Discord →
McTaba Labs logo

Educating 1 million students in tech by 2030.

Programs

  • HighSchool Graduates Launchpad
  • AI & Business Automation
  • Corporate Training
  • McTaba Story & Mission
  • Full-Stack Curriculum
  • Course Pricing & Plans
  • Frequently Asked Questions

Resources

  • Join Discord Community
  • Tech Events in Nairobi
  • Masterclasses
  • Free Resources
  • Learn
  • Campus
  • Africa Tech Talent Report
  • Partner With Us
  • Start a Project
  • Our Work

Contact Us

  • 124 Manyani East Road, Lavington, Nairobi
  • +254727795603
  • Book a Discovery Call

Office Hours:

Mon-Fri: 9am - 2pm EAT

Sat: 10am - 12pm EAT

© 2027 McTaba Labs - A product of Edtech Industries. All rights reserved.

Privacy PolicyTerms of ServiceRefund Policy
  1. Learn
  2. Paystack for African Developers
  3. Accept Payments with Paystack in Django REST Framework
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 20, 2026

Accept Payments with Paystack in Django REST Framework

To accept Paystack payments in DRF, create an APIView that receives email and amount via a serializer, initializes a transaction with the Paystack API, and returns the authorization URL as JSON. Your SPA or mobile frontend redirects to Paystack or opens the inline popup. A separate APIView verifies the payment.

In this article

  1. 1. Setup
  2. 2. Payment Serializer
  3. 3. Initialize Transaction APIView
  4. 4. Verify Payment APIView
  5. 5. URL Configuration
  6. 6. Frontend Integration
  7. 7. Security Notes
  8. 8. Ship Payments Faster

Setup

Install DRF and requests if not already installed:

pip install djangorestframework requests python-decouple

Add 'rest_framework' to INSTALLED_APPS in settings.py. Configure your Paystack keys as shown in the Django guide.

Payment Serializer

# payments/serializers.py
from rest_framework import serializers

class InitializePaymentSerializer(serializers.Serializer):
    email = serializers.EmailField()
    amount = serializers.DecimalField(max_digits=10, decimal_places=2, min_value=1)

class VerifyPaymentSerializer(serializers.Serializer):
    reference = serializers.CharField(max_length=100)

Get weekly developer tips

Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.

No spam. Unsubscribe anytime.

Initialize Transaction APIView

# payments/views.py
import uuid
import requests as http_requests
from django.conf import settings
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .serializers import InitializePaymentSerializer
from .models import Order

class InitializePaymentView(APIView):
    def post(self, request):
        serializer = InitializePaymentSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        email = serializer.validated_data['email']
        amount = serializer.validated_data['amount']
        reference = 'order_' + uuid.uuid4().hex[:12]

        # Save order to database
        order = Order.objects.create(
            email=email,
            amount=int(amount * 100),
            reference=reference,
        )

        # Call Paystack
        response = http_requests.post(
            'https://api.paystack.co/transaction/initialize',
            json={
                'email': email,
                'amount': order.amount,
                'reference': reference,
                'callback_url': request.build_absolute_uri('/api/payments/callback/'),
            },
            headers={
                'Authorization': 'Bearer ' + settings.PAYSTACK_SECRET_KEY,
                'Content-Type': 'application/json',
            },
        )

        result = response.json()

        if not result.get('status'):
            return Response(
                {'error': result.get('message', 'Initialization failed')},
                status=status.HTTP_400_BAD_REQUEST,
            )

        return Response({
            'authorization_url': result['data']['authorization_url'],
            'access_code': result['data']['access_code'],
            'reference': result['data']['reference'],
        })

Verify Payment APIView

# payments/views.py (continued)
from django.utils import timezone

class VerifyPaymentView(APIView):
    def get(self, request):
        reference = request.query_params.get('reference')

        if not reference:
            return Response(
                {'error': 'Missing reference'},
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Call Paystack verify
        response = http_requests.get(
            'https://api.paystack.co/transaction/verify/' + reference,
            headers={
                'Authorization': 'Bearer ' + settings.PAYSTACK_SECRET_KEY,
            },
        )

        result = response.json()

        if not result.get('status') or result['data']['status'] != 'success':
            return Response(
                {'error': 'Payment not successful'},
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Look up and validate order
        try:
            order = Order.objects.get(reference=reference)
        except Order.DoesNotExist:
            return Response(
                {'error': 'Order not found'},
                status=status.HTTP_404_NOT_FOUND,
            )

        if result['data']['amount'] != order.amount:
            return Response(
                {'error': 'Amount mismatch'},
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Idempotent fulfillment
        updated = Order.objects.filter(
            reference=reference, paid=False
        ).update(paid=True, paid_at=timezone.now())

        return Response({
            'success': True,
            'already_fulfilled': updated == 0,
            'amount': order.amount / 100,
            'currency': order.currency,
        })

URL Configuration

# payments/urls.py
from django.urls import path
from .views import InitializePaymentView, VerifyPaymentView

urlpatterns = [
    path('initialize/', InitializePaymentView.as_view(), name='initialize_payment'),
    path('verify/', VerifyPaymentView.as_view(), name='verify_payment'),
]
# project/urls.py
from django.urls import path, include

urlpatterns = [
    path('api/payments/', include('payments.urls')),
]

Frontend Integration

Your React, Vue, or mobile frontend calls the API:

// Frontend (React/Vue/etc.)
async function initializePayment(email, amount) {
  var res = await fetch('/api/payments/initialize/', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Token ' + authToken,
    },
    body: JSON.stringify({ email: email, amount: amount }),
  });

  var data = await res.json();

  if (data.authorization_url) {
    // Redirect checkout
    window.location.href = data.authorization_url;
  }
}

For inline popup, use the access_code with Paystack Inline.js. For redirect checkout, use the authorization_url.

Security Notes

  1. Authentication. Add authentication to your initialize endpoint so only logged-in users can start payments.
  2. Amount validation. Look up the correct price from your product catalog. Never trust the client-submitted amount.
  3. Webhooks. Set up a webhook endpoint for reliable payment notification. See Handle Paystack Webhooks in DRF.
  4. CORS. Configure django-cors-headers to allow requests from your frontend domain.

Ship Payments Faster

This guide is part of the Paystack integration guides by language and framework series.

Sign up for the McTaba newsletter

Key Takeaways

  • ✓DRF APIViews return JSON responses, making them ideal backends for React, Vue, Angular, or mobile apps using Paystack.
  • ✓Use serializers to validate payment input (email, amount) before calling the Paystack API.
  • ✓The Paystack secret key stays in your Django settings. The API returns only the authorization URL and access code to the client.
  • ✓Set authentication_classes and permission_classes appropriately. Initialize endpoints usually require authentication. Webhook endpoints require none.
  • ✓Amounts are in kobo (NGN), pesewas (GHS), or cents (ZAR/KES/USD). Validate and convert on the server.
  • ✓For inline popup checkout, return the access_code. For redirect checkout, return the authorization_url.

Frequently Asked Questions

Should I use function-based views or class-based APIViews?
APIViews are the DRF convention and give you built-in serializer validation, content negotiation, and authentication handling. Use them for consistency with the rest of your DRF API.
How do I add authentication to the payment endpoint?
Set authentication_classes = [TokenAuthentication] and permission_classes = [IsAuthenticated] on your APIView. DRF handles the rest. You can then use request.user to get the customer email.
Can I use ViewSets and Routers for Paystack endpoints?
ViewSets work best for CRUD operations on models. Payment initialization and verification are action-oriented, not model CRUD, so APIViews are a better fit.
How do I handle CORS with DRF and Paystack?
Install django-cors-headers and add your frontend domain to CORS_ALLOWED_ORIGINS. This has nothing to do with Paystack directly. It allows your SPA to call your DRF backend.

Learn Paystack Integration

KES 2,999

The definitive guide to building payment systems with Paystack — from your first transaction to production-grade payment infrastructure across Africa. 9 modules, 47 lessons. Free preview available.

Start Paystack Course

Not ready? Create Free Account

Keep reading

Paystack Integration Guides by Language and Framework

A complete directory of Paystack integration guides organized by programming language and framework. Each guide covers accepting payments, verifying transactions, handling webhooks, and building subscriptions in your specific stack.

Read more

Accept Payments with Paystack in Svelte and SvelteKit

Accept Paystack payments in SvelteKit using server endpoints for backend logic and Svelte components for the frontend. This guide covers initializing transactions, inline popup checkout, redirect checkout, and verification in a single full-stack SvelteKit project.

Read more

Handle Paystack Webhooks in Flask

Receive and verify Paystack webhooks in your Flask application. This guide covers accessing request.data for raw bytes, HMAC SHA-512 signature verification, processing charge.success events, and making handlers idempotent.

Read more

Build Paystack Subscriptions in ASP.NET Core

Implement Paystack recurring billing in ASP.NET Core. This guide covers creating plans, subscribing customers through transaction initialization, handling renewal webhooks with C#, and cancelling subscriptions.

Read more

Paystack Direct Debit: When and How to Use It

Direct debit lets you pull money directly from a customer bank account on a recurring schedule, without needing their card details. This guide covers how Paystack direct debit works, when it makes sense over card billing, and the mandate authorization flow your customers go through.

Read more

Paystack Mixed Content and HTTPS Errors

Your site is served over HTTP but Paystack scripts load over HTTPS. Modern browsers block this mix. The fix is to serve your entire site over HTTPS.

Read more

Explore related topics

M-Pesa & African Stack

M-Pesa Daraja API tutorials, USSD development, and WhatsApp Business API guides. The African Stack that global bootcamps do not teach.

Learn to Code in Kenya

Everything a Kenyan needs to know before writing their first line of code. Career paths, real costs, hardware requirements, and honest answers about what it takes.

Learning to Code

Roadmaps, language guides, and practical advice for learning to code and launching a programming career.

Breaking Into Tech

Practical, no-nonsense guides for anyone looking to start or change their career in tech. From choosing your first language to acing interviews.

The African Stack: Skills for This Market

The skills that make Kenyan developers hard to replace: M-Pesa, USSD, WhatsApp, fintech, and building for the African market.

Bonaventure Ogeto

Bonaventure Ogeto

Founder, McTaba Labs

Bonaventure is the founder of McTaba Labs, a coding bootcamp in Nairobi, Kenya. He has spent years building products for the African market and mentoring the next generation of developers across the continent.