Skip to main content

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

Metadata

Release files for dj-paynow 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dj-paynow 0.0.1
File Size Uploaded
dj_paynow-0.0.1.tar.gz 26.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dj-paynow 0.0.1
File Interpreter ABI Platform
dj_paynow-0.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 43.6 kB

Release files / dj_paynow-0.0.1.tar.gz

Download URL dj_paynow-0.0.1.tar.gz
Size 26.4 kB
Tags Source
SHA-256 checksum
How to use checksums
782be33f6949085099d0feaf7c779dc99bc492638e3caec69ddbf06977edb557
BLAKE2b-256 checksum
How to use checksums
e42b1af6f7168f5ca51949db2a10808e0e1ed1fa3fe378f433e3082781e47c33
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.19

Release files / dj_paynow-0.0.1-py3-none-any.whl

Download URL dj_paynow-0.0.1-py3-none-any.whl
Size 17.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
22da0780621fbe891257bb4bf1b20e8a569e8546a06736eb7987f6cb8bd30217
BLAKE2b-256 checksum
How to use checksums
b58ab598eae3c205501c01c844bcc3b1b6e29bfa3b06bc05820114be9a422a71
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.19

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page