Troubleshooting Guide
Solutions to common issues when using dj-payfast.
Quick Diagnosis
Use this flowchart to quickly identify your issue:
Can't install dj-payfast?
└─> See: Installation Issues
Payment not creating?
└─> See: Payment Creation Issues
Can't reach PayFast?
└─> See: Payment Processing Issues
Webhook not firing?
└─> See: Webhook Issues
Signature errors?
└─> See: Security/Signature Issues
Database errors?
└─> See: Database Issues
Installation Issues
Issue: pip install fails
Symptoms:
ERROR: Could not find a version that satisfies the requirement dj-payfast
Solutions:
Update pip:
python -m pip install --upgrade pip
Check Python version:
python --version # Must be 3.8+
Use specific version:
pip install dj-payfast==0.1.8
Install from GitHub:
pip install git+https://github.com/carrington-dev/dj-payfast.git
Issue: Import error after installation
Symptoms:
ImportError: No module named 'payfast'
Solutions:
Verify installation:
pip list | grep dj-payfast
Check virtual environment:
which python # Should be in your project's venv
Add to INSTALLED_APPS:
# settings.py INSTALLED_APPS = [ # ... 'payfast', # Add this ]
Run migrations:
python manage.py migrate
Payment Creation Issues
Issue: Payment form not displaying
Symptoms: Blank page or missing form
Solutions:
Check template exists:
# Verify template path 'payfast/checkout.html'
Check context data:
def checkout_view(request): # Ensure you're passing these return render(request, 'payfast/checkout.html', { 'form': form, 'payment': payment, })
Debug template:
{# In template #} {{ form.errors }} {{ payment }}
Issue: Missing required fields
Symptoms:
IntegrityError: NOT NULL constraint failed
Solution:
Ensure all required fields are provided:
# Required fields
payment = PayFastPayment.objects.create(
m_payment_id=str(uuid.uuid4()), # Required & unique
amount=99.99, # Required
item_name='Product Name', # Required
email_address='user@example.com', # Required
)
Issue: Duplicate payment_id error
Symptoms:
IntegrityError: UNIQUE constraint failed: payfast_payfastpayment.m_payment_id
Solutions:
Generate unique IDs:
import uuid m_payment_id = str(uuid.uuid4()) # Or timestamp-based: from django.utils import timezone m_payment_id = f"{user.id}_{int(timezone.now().timestamp())}"
Check for existing payment:
if PayFastPayment.objects.filter(m_payment_id=payment_id).exists(): # Reuse existing payment payment = PayFastPayment.objects.get(m_payment_id=payment_id) else: # Create new payment payment = PayFastPayment.objects.create(...)
Payment Processing Issues
Issue: Can’t reach PayFast
Symptoms: Connection timeout or error
Solutions:
Check internet connection:
ping sandbox.payfast.co.zaVerify PAYFAST_TEST_MODE:
# settings.py PAYFAST_TEST_MODE = True # For sandbox # False for production
Check firewall:
Ensure outbound HTTPS (port 443) is allowed
Issue: Redirect not working
Symptoms: Form submits but nothing happens
Solutions:
Check form action URL:
<form action="{{ form.get_action_url }}" method="post">
Verify merchant credentials:
# settings.py PAYFAST_MERCHANT_ID = '10000100' # Check this is correct PAYFAST_MERCHANT_KEY = '46f0cd694581a'
Check JavaScript errors:
Open browser console (F12) and look for errors
Issue: Payment stuck on “Processing”
Symptoms: Payment never completes or fails
Solutions:
Check webhook configuration:
notify_url = request.build_absolute_uri( reverse('payfast:notify') )
Verify webhook URL is accessible:
curl -X POST https://yourdomain.com/payfast/notify/ # Should return 405 "Method Not Allowed"
Check PayFast ITN logs:
Login to PayFast dashboard → ITN History
Webhook Issues
Issue: Webhook never fires
Symptoms: Payment completes but status stays “pending”
Solutions:
Verify webhook URL is public:
# Test from external server curl -X POST https://yourdomain.com/payfast/notify/
Check CSRF exemption:
dj-payfast does this automatically, but verify:
@csrf_exempt def webhook_view(request): pass
Use ngrok for local testing:
ngrok http 8000 # Use ngrok URL as notify_url
Check webhook logs:
from payfast.models import PayFastNotification # Check for recent notifications notifications = PayFastNotification.objects.all().order_by('-created_at')[:10] for notif in notifications: print(f"Valid: {notif.is_valid}") print(f"Errors: {notif.validation_errors}")
Issue: Webhook returns 403 Forbidden
Symptoms: Webhook fails with 403 error
Solutions:
Disable authentication requirement:
# Don't require login for webhook # dj-payfast handles this automatically
Check middleware:
Ensure no middleware is blocking the request
Verify ALLOWED_HOSTS:
# settings.py (production) ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com']
Issue: Webhook timeout
Symptoms: Webhook takes too long, PayFast retries
Solutions:
Respond quickly:
def webhook_view(request): # Process quickly payment_id = request.POST.get('m_payment_id') # Update database (fast) payment = PayFastPayment.objects.get(m_payment_id=payment_id) payment.mark_complete() # Queue slow tasks send_email.delay(payment.id) return HttpResponse('OK') # Respond fast!
Use Celery for slow tasks:
pip install celery redis
Optimize database queries:
# Use select_related to reduce queries payment = PayFastPayment.objects.select_related('user').get( m_payment_id=payment_id )
Security/Signature Issues
Issue: Signature verification failed
Symptoms:
Invalid signature
Solutions:
Check passphrase matches:
# settings.py PAYFAST_PASSPHRASE = 'YourExactPassphrase' # Must match PayFast dashboard exactly
Verify you’re using correct credentials:
# Sandbox if PAYFAST_TEST_MODE: PAYFAST_PASSPHRASE = 'SandboxPassphrase' # Production else: PAYFAST_PASSPHRASE = 'ProductionPassphrase'
Debug signature generation:
from payfast.utils import generate_signature # Generate signature data = { 'merchant_id': '10000100', 'amount': '100.00', 'item_name': 'Test', } signature = generate_signature(data, 'YourPassphrase') print(f"Generated: {signature}")
Check for whitespace:
# Remove any whitespace from passphrase PAYFAST_PASSPHRASE = 'YourPassphrase'.strip()
Issue: IP validation failing
Symptoms: Webhook rejected due to invalid IP
Solutions:
Check if behind proxy:
def get_client_ip(request): x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: ip = x_forwarded_for.split(',')[0] else: ip = request.META.get('REMOTE_ADDR') return ip
Configure nginx for proxies:
location /payfast/ { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; proxy_pass http://your-app; }
Temporarily disable for testing:
# Only for debugging! # utils.py def validate_ip(ip_address): return True # REMOVE THIS IN PRODUCTION!
Database Issues
Issue: Migration errors
Symptoms:
django.db.utils.OperationalError: no such table
Solutions:
Run migrations:
python manage.py migrate payfast
Check migrations exist:
python manage.py showmigrations payfast
Create missing migrations:
python manage.py makemigrations payfast python manage.py migrate
Issue: Database locked
Symptoms (SQLite):
database is locked
Solutions:
Use PostgreSQL in production:
# settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'your_db', } }
Increase SQLite timeout:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': 'db.sqlite3', 'OPTIONS': { 'timeout': 20, } } }
Configuration Issues
Issue: Settings not found
Symptoms:
AttributeError: 'Settings' object has no attribute 'PAYFAST_MERCHANT_ID'
Solution:
Add required settings:
# settings.py
PAYFAST_MERCHANT_ID = '10000100'
PAYFAST_MERCHANT_KEY = '46f0cd694581a'
PAYFAST_PASSPHRASE = 'your_passphrase'
PAYFAST_TEST_MODE = True
Issue: Environment variables not loading
Symptoms: Settings show None or empty values
Solutions:
Install python-decouple:
pip install python-decouple
Create .env file:
# .env PAYFAST_MERCHANT_ID=10000100 PAYFAST_MERCHANT_KEY=46f0cd694581a PAYFAST_PASSPHRASE=your_passphrase
Load in settings:
# settings.py from decouple import config PAYFAST_MERCHANT_ID = config('PAYFAST_MERCHANT_ID') PAYFAST_MERCHANT_KEY = config('PAYFAST_MERCHANT_KEY')
Add .env to .gitignore:
# .gitignore .env *.env
Template Issues
Issue: Template not found
Symptoms:
TemplateDoesNotExist: payfast/checkout.html
Solutions:
Check INSTALLED_APPS order:
INSTALLED_APPS = [ 'payfast', # Should be here # Your apps can override templates if listed after ]
Verify APP_DIRS:
TEMPLATES = [{ 'APP_DIRS': True, # Must be True }]
Create custom template:
mkdir -p templates/payfast cp venv/lib/python3.x/site-packages/payfast/templates/payfast/checkout.html \ templates/payfast/
Issue: Static files not loading
Symptoms: CSS/images missing
Solutions:
Collect static files:
python manage.py collectstatic
Configure static settings:
# settings.py STATIC_URL = '/static/' STATIC_ROOT = BASE_DIR / 'staticfiles'
Performance Issues
Issue: Slow payment creation
Solutions:
Optimize database queries:
# Use select_related for foreign keys payment = PayFastPayment.objects.select_related('user').get(id=1)
Add database indexes:
class PayFastPayment(models.Model): m_payment_id = models.CharField(max_length=100, db_index=True)
Use connection pooling:
pip install django-db-connection-pool
Issue: Webhook processing slow
Solutions:
Use async tasks:
from celery import shared_task @shared_task def process_webhook(payment_id): # Process in background pass
Optimize validation:
# Cache PayFast IP addresses from django.core.cache import cache def get_payfast_ips(): ips = cache.get('payfast_ips') if not ips: ips = resolve_payfast_hosts() cache.set('payfast_ips', ips, 3600) return ips
Getting Help
If you can’t solve your issue:
Check Existing Issues:
Enable Debug Logging:
# settings.py LOGGING = { 'version': 1, 'handlers': { 'console': { 'class': 'logging.StreamHandler', }, }, 'loggers': { 'payfast': { 'handlers': ['console'], 'level': 'DEBUG', }, }, }
Gather Information:
Django version:
python manage.py --versiondj-payfast version:
pip show dj-payfastPython version:
python --versionError messages and stack traces
Relevant configuration (without credentials!)
Create Issue:
Next Steps
security - Security best practices
API Reference - Complete API reference
Frequently Asked Questions (FAQ) - Frequently asked questions