@damisile_ayoola/hook-nest
v1.0.0
Published
Developer-first local webhook relay & debugger with first-class support for Paystack, Flutterwave, Stripe, and GitHub. Inspect, replay, and verify HMAC signatures — all from a beautiful real-time Web Inspector UI.
Maintainers
Readme
The Problem
You're integrating Paystack or Stripe webhooks. You set up your endpoint, trigger a test payment, and... nothing. Your localhost isn't reachable. You fire up ngrok, get a URL, paste it into the dashboard, trigger another payment. The signature verification fails — your framework silently re-serialized the JSON body. You add express.raw(), break your other routes, fix that, trigger another payment...
HookNest eliminates this entire loop.
How It Works
┌──────────────┐ ┌─────────────────┐ ┌──────────────────┐
│ Paystack / │────▶│ HookNest │────▶│ Your Local API │
│ Stripe / │ │ localhost:4000 │ │ localhost:3000 │
│ GitHub │ │ │ │ /api/webhook │
└──────────────┘ │ ✅ Raw body │ └──────────────────┘
│ ✅ HMAC intact │
│ ✅ Web UI │
│ ✅ Replay │
└─────────────────┘✨ Features
| Feature | Description |
|---------|-------------|
| ⚡ Zero-Config Relay | Forward any webhook to your local server with --to http://localhost:3000/api/webhook |
| 🔐 Raw Body Preservation | Byte-for-byte Buffer preservation — never corrupt HMAC signatures |
| 🇳🇬 African Gateway First | Native detection for Paystack (SHA512), Flutterwave (verif-hash), Stripe (SHA256), GitHub |
| 🖥️ Real-time Web Inspector | Live dark-mode dashboard at localhost:4000 with SSE streaming |
| 🔁 1-Click Replay | Re-fire any webhook without repeating test payments |
| 🧪 Mock Generator | 5 built-in templates — trigger Paystack charge.success, Stripe payment_intent.succeeded, etc. |
| 🔑 Signature Verifier | Paste your secret key → instant HMAC validation with timing-safe comparison |
| 🌍 Public Tunnel | --tunnel generates a free public URL for gateway dashboards |
| 🧹 Noise Filtering | Auto-ignores favicon, source maps, and browser GET requests |
🚀 Quick Start
Run Instantly with NPX
npx @damisile_ayoola/hook-nest --to http://localhost:3000/api/webhookInstall Globally
npm install -g @damisile_ayoola/hook-nest
hook-nest --to http://localhost:3000/api/webhookWith Public Tunnel
npx @damisile_ayoola/hook-nest --to http://localhost:3000/api/webhook --tunnelThen paste the public URL into your Paystack/Stripe webhook settings.
🛠️ CLI Options
| Flag | Description | Default |
|------|-------------|---------|
| -p, --port <number> | Port for webhook receiver & dashboard | 4000 |
| -t, --to <url> | Local endpoint to forward webhooks to | — |
| --tunnel | Open a public internet tunnel via localtunnel | false |
| --tunnel-subdomain <name> | Request a specific subdomain for tunnel | — |
| -V, --version | Show version number | — |
| -h, --help | Show help | — |
🖥️ Web Inspector Dashboard
Open http://localhost:4000 in your browser after starting HookNest.
What You Can Do
- 📦 Payload Tab — View formatted JSON or raw text with 1-click copy
- 📋 Headers Tab — Full HTTP headers table with copy support
- 🎯 Target Response — See your backend's status code, latency (ms), and response body
- 🔑 Signature Verifier — Enter your Paystack
sk_test_...or Stripewhsec_...key to verify HMAC - ⚡ Mock Drawer — Pick from 5 templates and fire a realistic webhook into your pipeline
- 🔍 Search & Filter — Filter events by provider (Paystack, Stripe, etc.) or search payloads
🧪 Mock Webhook Templates
HookNest ships with production-accurate mock payloads:
| Template | Provider | Event |
|----------|----------|-------|
| Paystack Card Payment | Paystack | charge.success (₦25,000) |
| Paystack Bank Payout | Paystack | transfer.success |
| Flutterwave Checkout | Flutterwave | charge.completed ($50) |
| Stripe PaymentIntent | Stripe | payment_intent.succeeded ($120) |
| GitHub Pull Request | GitHub | pull_request.opened |
🔐 Signature Verification
HookNest verifies webhook signatures using timing-safe HMAC comparison:
| Provider | Algorithm | Header |
|----------|-----------|--------|
| Paystack | HMAC-SHA512 | x-paystack-signature |
| Stripe | HMAC-SHA256 (timestamped) | stripe-signature |
| GitHub | HMAC-SHA256 | x-hub-signature-256 |
| Flutterwave | Direct hash match | verif-hash |
🏗️ Architecture
hook-nest/
├── bin/
│ └── hook-nest.js # CLI entrypoint (Commander.js)
├── src/
│ ├── server.js # Express app — API routes + webhook ingestion
│ ├── store.js # In-memory EventEmitter circular buffer (100 events)
│ ├── gateways.js # Auto gateway detection + HMAC verification
│ ├── forwarder.js # Webhook proxy with latency tracking
│ ├── mocks.js # 5 mock webhook templates
│ └── index.js # Library barrel export
├── public/
│ ├── index.html # Web Inspector UI
│ ├── app.js # Vanilla JS frontend (SSE, tabs, modals)
│ └── style.css # Custom styles (Tailwind via CDN)
└── test/
└── test-relay.js # E2E integration testsKey Design Decisions
express.raw()for webhooks,express.json()for APIs — Conditional body parsing ensures cryptographic signatures remain intact while dashboard APIs work normally.- EventEmitter + SSE — The
EventStoreemits events that the SSE endpoint streams to the browser in real-time. No WebSocket complexity. - Circular buffer (100 events) — Memory-safe. Old events are automatically evicted.
- No build step for UI — Tailwind via CDN + vanilla JS. Zero
npm run buildneeded.
🧑💻 Programmatic Usage
HookNest can be used as a library in your own Node.js projects:
import { createHookNestApp } from 'hook-nest';
const app = createHookNestApp({
port: 4000,
targetUrl: 'http://localhost:3000/api/webhook'
});
app.listen(4000, () => {
console.log('HookNest running on port 4000');
});🧪 Running Tests
npm testRuns 5 end-to-end integration tests:
- Paystack webhook ingestion with byte-for-byte raw body preservation ✅
- Event store recording with forward status 200 OK ✅
- HMAC-SHA512 signature verification (valid + rejected invalid) ✅
- Flutterwave mock trigger ✅
- Event replay to local target ✅
🤝 Contributing
See CONTRIBUTING.md for guidelines. PRs are welcome!
