Django Paynow integration library for South African payments
Project description
dj-paynow - Django + PayNow Made Easy
Complete PayNow payment gateway integration for Django applications. Accept payments from Zimbabwean customers using EcoCash, OneMoney, Visa/Mastercard, and more.
Introduction
dj-paynow is a comprehensive Django library for integrating PayNow, Zimbabwe's leading payment gateway. It provides a simple, secure, and Pythonic way to accept online payments.
Features
- Easy Integration - Get started in under 10 minutes
- Multiple Payment Methods - EcoCash, OneMoney, TeleCash, Visa/Mastercard
- Secure - Hash verification and validation
- Complete - Models, forms, views, and webhooks included
- Database Tracking - Complete payment history
- Django Admin - Full admin integration
- REST API - Optional DRF support
- Status Polling - Real-time payment status updates
Requirements
- Python 3.8+
- Django 3.2+
- Django REST Framework 3.12+
- requests 2.25.0+
- PayNow Account (sign up at paynow.co.zw)
Installation
1. Install via pip
pip install dj-paynow
2. Add to INSTALLED_APPS
# settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Third-party apps
'rest_framework', # Optional, for API support
'paynow', # Add this
# Your apps
'myapp',
]
3. Configure Settings
Add your PayNow credentials to settings.py:
# PayNow Configuration
PAYNOW_INTEGRATION_ID = 'your_integration_id'
PAYNOW_INTEGRATION_KEY = 'your_integration_key'
PAYNOW_TEST_MODE = True # False for production
Environment Variables (Recommended):
pip install dotzen
from dotzen import config
PAYNOW_INTEGRATION_ID = config('PAYNOW_INTEGRATION_ID')
PAYNOW_INTEGRATION_KEY = config('PAYNOW_INTEGRATION_KEY')
PAYNOW_TEST_MODE = config('PAYNOW_TEST_MODE', 'True') == 'True'
4. Configure URLs
# urls.py
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('paynow/', include('paynow.urls')),
]
5. Run Migrations
python manage.py migrate
Quick Start
Create a Payment
from django.shortcuts import redirect, reverse
from urllib.parse import urlencode
def buy_product(request):
"""Create payment and redirect to PayNow"""
params = urlencode({
'amount': '50.00',
'description': 'Premium Subscription',
'email': request.user.email,
'phone': '+263771234567',
})
url = f"{reverse('paynow:checkout')}?{params}"
return redirect(url)
Using the API
import requests
# Create payment
response = requests.post('http://localhost:8000/paynow/payments/', json={
'amount': '100.00',
'description': 'Product Purchase',
'email': 'customer@example.com',
'phone': '+263771234567',
})
payment = response.json()
# Redirect user to payment['paynow_url']
Payment Flow
- Create Payment - Create a payment record with amount and description
- Initialize with PayNow - Send request to PayNow to get payment URL
- Redirect User - Redirect customer to PayNow payment page
- Customer Pays - Customer completes payment via EcoCash/OneMoney/Card
- Receive Webhook - PayNow sends status update to your webhook
- Poll Status - Optionally poll for payment status
- Update Status - Payment status updated in database
Payment Methods
PayNow supports multiple payment methods:
- EcoCash - Mobile money (most popular in Zimbabwe)
- OneMoney - NetOne mobile money
- TeleCash - Telecel mobile money
- Visa/Mastercard - Credit and debit cards
Customers choose their preferred method on the PayNow payment page.
Webhook Handling
PayNow sends notifications to your result URL when payment status changes:
# Webhook endpoint: /paynow/result/
# This is handled automatically by dj-paynow
# You can add custom logic using Django signals:
from django.db.models.signals import post_save
from django.dispatch import receiver
from paynow.models import PayNowPayment
@receiver(post_save, sender=PayNowPayment)
def handle_payment_complete(sender, instance, **kwargs):
if instance.status == 'paid':
# Grant access to service
grant_premium_access(instance.user)
# Send confirmation email
send_confirmation_email(instance)
Status Polling
Check payment status programmatically:
from paynow.paynow_client import PayNowClient
client = PayNowClient()
payment = PayNowPayment.objects.get(reference='PN123456789')
if payment.poll_url:
status = client.check_transaction_status(payment.poll_url)
if status['success']:
print(f"Status: {status['status']}")
print(f"Reference: {status['paynow_reference']}")
Models
PayNowPayment
Stores payment transaction data:
payment = PayNowPayment.objects.create(
user=request.user,
amount=99.99,
description='Premium Plan',
email='user@example.com',
phone='+263771234567',
)
Fields:
reference- Unique payment referenceamount- Payment amount (decimal)description- Payment descriptionemail- Customer emailphone- Customer phone numberstatus- Payment status (pending, sent, paid, failed, etc.)poll_url- URL for status pollingbrowser_url- PayNow payment page URLpaynow_reference- PayNow internal reference
PayNowStatusUpdate
Logs all status updates and webhook calls:
updates = payment.status_updates.all()
for update in updates:
print(f"{update.status} at {update.created_at}")
Django Admin
Full admin interface included:
- View all payments
- Filter by status, date
- Search by reference, email
- View status update history
- Manual status updates
Access at: /admin/paynow/
REST API
Optional REST API endpoints:
GET /paynow/payments/ - List payments
POST /paynow/payments/ - Create payment
GET /paynow/payments/{reference}/ - Get payment details
Security
dj-paynow implements security best practices:
- Hash Verification - All responses verified with SHA512 hash
- Status Logging - All webhook calls logged for audit
- Environment Variables - Credentials stored securely
- HTTPS Required - Production requires HTTPS
Testing
PayNow provides a sandbox environment for testing:
- Sign up at paynow.co.zw
- Get sandbox credentials
- Set
PAYNOW_TEST_MODE = True - Test with EcoCash sandbox numbers
Examples
Subscription Payment
def subscribe_to_plan(request, plan_id):
plan = get_object_or_404(Plan, id=plan_id)
params = urlencode({
'amount': plan.price,
'description': f'{plan.name} Subscription',
'email': request.user.email,
})
return redirect(f"{reverse('paynow:checkout')}?{params}")
Donation Widget
def process_donation(request):
if request.method == 'POST':
amount = request.POST.get('amount')
email = request.POST.get('email')
params = urlencode({
'amount': amount,
'description': 'Donation',
'email': email,
})
return redirect(f"{reverse('paynow:checkout')}?{params}")
return render(request, 'donate.html')
Getting PayNow Credentials
- Visit paynow.co.zw
- Sign up for an account
- Navigate to Settings → Integrations
- Copy your Integration ID and Integration Key
- Add them to your environment variables
Troubleshooting
Payment not updating?
- Check webhook URL is publicly accessible
- Verify hash in status updates
- Check PayNow status update logs in admin
Hash verification failing?
- Ensure integration key is correct
- Check for extra spaces in credentials
Webhook not receiving calls?
- Use ngrok for local development
- Verify result URL is correct
- Check server logs for errors
Support
- GitHub: github.com/carrington-dev/dj-paynow
- Issues: GitHub Issues
- Email: carrington.muleya@outlook.com
- PayNow Docs: paynow.co.zw/developers
Contributing
Contributions welcome! Please see CONTRIBUTING.md
License
MIT License - See LICENSE file
Acknowledgments
Inspired by:
Changelog
0.1.0 (2025-12-15)
- Initial release
- PayNow integration
- Payment models
- Webhook handling
- Status polling
- REST API
- Django admin
Made with ❤️ for the Zimbabwean developer community
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dj_paynow-0.0.1.tar.gz.
File metadata
- Download URL: dj_paynow-0.0.1.tar.gz
- Upload date:
- Size: 26.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
782be33f6949085099d0feaf7c779dc99bc492638e3caec69ddbf06977edb557
|
|
| MD5 |
8cc0e4da3ccd25fb58a96f5106405577
|
|
| BLAKE2b-256 |
e42b1af6f7168f5ca51949db2a10808e0e1ed1fa3fe378f433e3082781e47c33
|
File details
Details for the file dj_paynow-0.0.1-py3-none-any.whl.
File metadata
- Download URL: dj_paynow-0.0.1-py3-none-any.whl
- Upload date:
- Size: 17.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
22da0780621fbe891257bb4bf1b20e8a569e8546a06736eb7987f6cb8bd30217
|
|
| MD5 |
196c99e143a4992746114e7e7e60d285
|
|
| BLAKE2b-256 |
b58ab598eae3c205501c01c844bcc3b1b6e29bfa3b06bc05820114be9a422a71
|