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.