Why Paystack Over Stripe for African Apps

Stripe is brilliant but its support for African bank accounts and mobile money is limited. Paystack supports GHS, NGN, KES, ZAR, and crucially - Mobile Money. For any app targeting Ghana or Nigeria, Paystack is the right choice.

Setting Up

pip install requests  # Paystack has no official Python SDK - raw requests is fine
# settings.py
PAYSTACK_SECRET_KEY = os.getenv("PAYSTACK_SECRET_KEY")
PAYSTACK_PUBLIC_KEY = os.getenv("PAYSTACK_PUBLIC_KEY")

Initiating a Payment

import hmac, hashlib, requests
from django.conf import settings

def initialize_payment(email, amount_ghs, reference, callback_url):
    """amount in pesewas (1 GHS = 100 pesewas)"""
    response = requests.post(
        "https://api.paystack.co/transaction/initialize",
        headers={"Authorization": f"Bearer {settings.PAYSTACK_SECRET_KEY}"},
        json={
            "email": email,
            "amount": int(amount_ghs * 100),
            "reference": reference,
            "callback_url": callback_url,
            "currency": "GHS",
        }
    )
    return response.json()

Webhook Verification (Critical)

Never trust a callback without verifying the Paystack signature:

def verify_paystack_signature(request):
    paystack_signature = request.headers.get("X-Paystack-Signature", "")
    body = request.body
    secret = settings.PAYSTACK_SECRET_KEY.encode()
    computed = hmac.new(secret, body, hashlib.sha512).hexdigest()
    return hmac.compare_digest(computed, paystack_signature)

class PaystackWebhookView(APIView):
    permission_classes = []

    def post(self, request):
        if not verify_paystack_signature(request):
            return Response(status=400)

        event = request.data.get("event")
        data  = request.data.get("data", {})

        if event == "charge.success":
            handle_successful_payment(data)

        return Response({"status": "ok"})

Idempotency

Always check if a reference was already processed before marking it paid. Use a Transaction model with a unique constraint on reference and status.

I've used this exact pattern on ColetPay, UGC's fee collection system, and NHIA's portal - it's battle-tested.