Skip to main content

Django Paynow integration library for South African payments

Project description

dj-paynow - Django + PayNow Made Easy

PyPI version Python versions Django versions License

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

  1. Create Payment - Create a payment record with amount and description
  2. Initialize with PayNow - Send request to PayNow to get payment URL
  3. Redirect User - Redirect customer to PayNow payment page
  4. Customer Pays - Customer completes payment via EcoCash/OneMoney/Card
  5. Receive Webhook - PayNow sends status update to your webhook
  6. Poll Status - Optionally poll for payment status
  7. 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 reference
  • amount - Payment amount (decimal)
  • description - Payment description
  • email - Customer email
  • phone - Customer phone number
  • status - Payment status (pending, sent, paid, failed, etc.)
  • poll_url - URL for status polling
  • browser_url - PayNow payment page URL
  • paynow_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:

  1. Hash Verification - All responses verified with SHA512 hash
  2. Status Logging - All webhook calls logged for audit
  3. Environment Variables - Credentials stored securely
  4. HTTPS Required - Production requires HTTPS

Testing

PayNow provides a sandbox environment for testing:

  1. Sign up at paynow.co.zw
  2. Get sandbox credentials
  3. Set PAYNOW_TEST_MODE = True
  4. 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

  1. Visit paynow.co.zw
  2. Sign up for an account
  3. Navigate to Settings → Integrations
  4. Copy your Integration ID and Integration Key
  5. 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

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dj_paynow-0.0.1.tar.gz (26.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dj_paynow-0.0.1-py3-none-any.whl (17.2 kB view details)

Uploaded Python 3

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

Hashes for dj_paynow-0.0.1.tar.gz
Algorithm Hash digest
SHA256 782be33f6949085099d0feaf7c779dc99bc492638e3caec69ddbf06977edb557
MD5 8cc0e4da3ccd25fb58a96f5106405577
BLAKE2b-256 e42b1af6f7168f5ca51949db2a10808e0e1ed1fa3fe378f433e3082781e47c33

See more details on using hashes here.

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

Hashes for dj_paynow-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 22da0780621fbe891257bb4bf1b20e8a569e8546a06736eb7987f6cb8bd30217
MD5 196c99e143a4992746114e7e7e60d285
BLAKE2b-256 b58ab598eae3c205501c01c844bcc3b1b6e29bfa3b06bc05820114be9a422a71

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page