Django Signals
paystack-django dispatches Django signals when webhook events are processed, allowing you to hook into the payment lifecycle without modifying library code.
Available Signals
All signals are defined in djpaystack.signals:
Signal |
Triggered when |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Connecting to Signals
Use Django’s @receiver decorator:
from django.dispatch import receiver
from djpaystack.signals import (
paystack_payment_successful,
)
@receiver(paystack_payment_successful)
def on_payment_success(sender, data, **kwargs):
"""Called when a charge.success webhook is processed."""
reference = data['reference']
amount = data['amount'] # in kobo
# Fulfil the order, send receipt, etc.
Best Practice: Register in apps.py
Create a signals.py module in your app and import it from ready():
# myapp/apps.py
from django.apps import AppConfig
class MyAppConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'myapp'
def ready(self):
import myapp.signals # noqa: F401
# myapp/signals.py
from django.dispatch import receiver
from django.utils import timezone
from djpaystack.signals import paystack_payment_successful
from .models import Order
@receiver(paystack_payment_successful)
def fulfil_order(sender, data, **kwargs):
try:
order = Order.objects.get(reference=data['reference'])
order.status = 'paid'
order.paid_at = timezone.now()
order.save()
except Order.DoesNotExist:
pass # Log or handle missing order
Multiple Events
Subscribe to several signals in the same module:
from django.dispatch import receiver
from djpaystack.signals import (
paystack_payment_successful,
paystack_subscription_created,
paystack_transfer_successful,
paystack_refund_processed,
paystack_dispute_created,
paystack_invoice_created,
paystack_customeridentification_success,
)
@receiver(paystack_payment_successful)
def on_payment(sender, data, **kwargs):
...
@receiver(paystack_subscription_created)
def on_subscription(sender, data, **kwargs):
...
@receiver(paystack_transfer_successful)
def on_transfer(sender, data, **kwargs):
...
@receiver(paystack_refund_processed)
def on_refund(sender, data, **kwargs):
...
@receiver(paystack_dispute_created)
def on_dispute(sender, data, **kwargs):
...
@receiver(paystack_invoice_created)
def on_invoice(sender, data, **kwargs):
...
@receiver(paystack_customeridentification_success)
def on_customer_verified(sender, data, **kwargs):
...
Disabling Signals
Set ENABLE_SIGNALS to False to suppress all signal dispatch:
PAYSTACK = {
'SECRET_KEY': 'sk_...',
'ENABLE_SIGNALS': False,
}
Best Practices
Keep handlers fast — Offload long-running work to Celery or Django-Q.
Use try/except — A failing handler should not crash the webhook response.
Test in isolation — Send signals manually in unit tests:
from djpaystack.signals import paystack_payment_successful paystack_payment_successful.send( sender=None, data={'reference': 'test_ref', 'amount': 50000}, )
Log signal events — Helps diagnose missed or double-processed payments.