Webhook Testing
Test webhooks locally using Paystack CLI's built-in ngrok integration.
Overview
Webhook testing typically requires deploying your application to a public server. Paystack CLI makes this easy by:
- Creating an ngrok tunnel to your local server
- Automatically updating your Paystack webhook URL
- Forwarding all webhook events to your local endpoint
Prerequisites
1. Get Ngrok Auth Token
Sign up at ngrok.com and get your auth token from dashboard.ngrok.com/get-started/your-authtoken
2. Configure the Token
paystack-cli config
# Select "Ngrok Auth Token"
# Paste your tokenOr set it via environment variable:
export NGROK_AUTH_TOKEN="your_token_here"Setting Up Webhook Listener
Start the Listener
paystack-cli webhook listen [local_route]If you don't provide a route, you'll be prompted:
$ paystack-cli webhook listen
Enter the local route to listen on for webhooks: http://localhost:3000/webhookWhat Happens
When you start the listener:
- Ngrok tunnel is created to your local server
- Webhook URL is updated in your Paystack integration
- Events are forwarded to your local endpoint automatically
- You'll see real-time webhook events in your terminal
Example Output
$ paystack-cli webhook listen http://localhost:3000/webhook
✓ Listening for incoming webhook events at http://localhost:3000/webhook
INFO: Press Ctrl+C to stop listening for webhook events.
Webhook URL: https://abc123.ngrok.ioTesting Webhooks
Using webhook ping
While the listener is running, open another terminal and send test events:
# Test charge success
paystack-cli webhook ping --event=charge.success
# Test transfer success
paystack-cli webhook ping --event=transfer.success
# Test failed transfer
paystack-cli webhook ping --event=transfer.failed
# Test subscription creation
paystack-cli webhook ping --event=subscription.createReal Transaction Testing
You can also trigger webhooks by performing real actions:
# Initialize a transaction
paystack-cli transaction:initialize \
--email=test@example.com \
--amount=10000
# Complete the payment through the returned authorization URL
# The webhook will be sent to your local endpointAvailable Webhook Events
The CLI supports testing these webhook events:
| Event | Description |
|---|---|
charge.success | Successful payment transaction |
transfer.success | Successful money transfer |
transfer.failed | Failed transfer attempt |
subscription.create | New subscription created |
Advanced Options
Specify Domain
Use test or live mode webhooks:
# Test mode (default)
paystack-cli webhook listen http://localhost:3000/webhook --domain=test
# Live mode
paystack-cli webhook listen http://localhost:3000/webhook --domain=liveForward to Specific URL
Override the saved webhook URL:
paystack-cli webhook listen http://localhost:3000/webhook \
--forward=https://your-custom-url.com/webhookCustom Ngrok Domain
If you have a paid ngrok plan with a custom domain:
export NGROK_DOMAIN="your-subdomain.ngrok.io"
paystack-cli webhook listen http://localhost:3000/webhookWebhook Handler Example
Here's an example Express.js webhook handler:
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
app.post('/webhook', (req, res) => {
// Verify webhook signature
const hash = crypto
.createHmac('sha512', process.env.PAYSTACK_SECRET_KEY)
.update(JSON.stringify(req.body))
.digest('hex');
if (hash === req.headers['x-paystack-signature']) {
const event = req.body;
// Handle the event
console.log('Event:', event.event);
console.log('Data:', event.data);
// Perform actions based on event type
switch(event.event) {
case 'charge.success':
// Handle successful charge
break;
case 'transfer.success':
// Handle successful transfer
break;
// ... other events
}
res.sendStatus(200);
} else {
res.sendStatus(400);
}
});
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
});Troubleshooting
"Ngrok token not configured"
Solution: Configure your ngrok auth token
paystack-cli config
# Select "Ngrok Auth Token" and enter your token"Port already in use"
Solution: Either:
- Stop the process using that port
- Use a different port in your local route
- Kill existing ngrok process:
pkill ngrok
Webhook not received
Checklist:
- Is the listener running? Check terminal output
- Is your local server running on the specified port?
- Is the route correct? (e.g.,
/webhooknot/webhooks) - Check firewall/antivirus settings
"Session expired"
Solution: Your CLI session expired, login again:
paystack-cli loginBest Practices
- Use Test Mode - Always use test mode for webhook testing
- Verify Signatures - Always verify webhook signatures in production
- Log Events - Log all webhook events for debugging
- Handle Duplicates - Webhooks may be sent multiple times, implement idempotency
- Return 200 Quickly - Acknowledge receipt immediately, process asynchronously
Next Steps
- Learn about Examples for webhook handling patterns
- Explore the API Reference for triggering events
- Read about Troubleshooting common issues