A simple local webhook receiver and relay tool
Project description
fasthook 🪝
A dead-simple local webhook receiver for testing and development. Because sometimes you just need to see what's being sent to your endpoint.
pip install fasthook
fasthook listen 3000
That's it. You're now catching webhooks on http://localhost:3000.
Why?
You know that moment when you're integrating a third-party service and you need to see what they're actually sending to your webhook? Or when you're testing a payment provider's IPN callbacks locally? Yeah, that's what this is for.
No tunnels, no forwarding services, no accounts. Just a local server that shows you everything that hits it.
Installation
pip install fasthook
Requires Python 3.8 or higher.
Quick Start
Start listening on port 3000:
fasthook listen 3000
Now any request to http://localhost:3000/* will be captured and displayed in your terminal.
Features
See everything: Method, path, headers, query params, body (JSON or raw)
Save to file: Log all events to a JSON file for later analysis
Forward requests: Relay incoming webhooks to another URL (like your actual endpoint)
Pretty output: Optional pretty-printed JSON for easier reading
Quiet mode: Suppress output when you just want to save/forward
Usage Examples
Basic listening:
fasthook listen 3000
Save all events to a file:
fasthook listen 3000 --save events.json
Forward to your actual endpoint:
fasthook listen 3000 --forward http://example.com/webhook
Do everything at once:
fasthook listen 3000 --save events.json --forward http://example.com/webhook --pretty
Bind to a different host:
fasthook listen 3000 --host 0.0.0.0
Run quietly (only show errors):
fasthook listen 3000 --save events.json --quiet
What You'll See
When a webhook hits your endpoint, you'll see something like this:
============================================================
[2025-01-15T10:30:45.123Z] POST /webhook/stripe
IP: 192.168.1.100
Query: {'test': 'true'}
Headers:
content-type: application/json
user-agent: Stripe/1.0
stripe-signature: t=123456,v1=abcdef...
JSON Body:
{
"id": "evt_123",
"type": "payment_intent.succeeded",
"data": {
"object": {
"id": "pi_123",
"amount": 2000,
"currency": "usd"
}
}
}
============================================================
Command Options
fasthook listen PORT [OPTIONS]
Arguments:
PORT Port number to listen on (required)
Options:
--save PATH Save events to a JSON file (newline-delimited)
--forward URL Forward all requests to this URL
--pretty Pretty-print JSON output to console
--quiet Suppress console output (except errors)
--host HOST Host to bind to (default: 127.0.0.1)
--debug Run in debug mode
--help Show help message
Saved Events Format
When using --save, events are saved as newline-delimited JSON. Each line is a complete event:
{"timestamp": "2025-01-15T10:30:45.123Z", "method": "POST", "path": "/webhook", "headers": {...}, "query": {...}, "json": {...}, "raw": "", "ip": "192.168.1.100"}
This format is easy to parse and works great with tools like jq:
# Pretty print all events
cat events.json | jq '.'
# Filter POST requests only
cat events.json | jq 'select(.method == "POST")'
# Count events by path
cat events.json | jq -r '.path' | sort | uniq -c
Testing
We use pytest with full async support. The test suite has 100% success rate with 98% code coverage.
Run tests:
pytest
Development
# Clone the repo
git clone https://github.com/Jermy-tech/fasthook.git
cd fasthook
# Install in development mode
pip install -e .
# Run fasthook
fasthook listen 3000
Common Use Cases
Testing Stripe webhooks locally:
fasthook listen 3000 --save stripe-events.json --pretty
Debugging third-party API callbacks:
fasthook listen 8080 --forward http://localhost:5000/api/callback
Recording webhook payloads for documentation:
fasthook listen 3000 --save examples.json --pretty
Running a mock webhook endpoint in CI/CD:
fasthook listen 9000 --quiet --save test-webhooks.json
How It Works
fasthook is built on FastAPI and Uvicorn. It creates a catch-all route that accepts any HTTP method on any path, logs the request details, and optionally saves or forwards the data.
The server runs asynchronously, so it can handle multiple concurrent requests without blocking. When forwarding is enabled, requests are relayed with the same method, headers, and body (minus the host header).
License
MIT License - see LICENSE file for details.
Contributing
Found a bug? Want a feature? Pull requests are welcome!
Author
Built by Jermy Pena
Links
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fasthook-1.0.1.tar.gz.
File metadata
- Download URL: fasthook-1.0.1.tar.gz
- Upload date:
- Size: 12.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5badbe46e31ae371d142863f56fefb13419728069f162fc806b24ff4e66b10a5
|
|
| MD5 |
cf3145b9a28f62254c6b78ee2125416d
|
|
| BLAKE2b-256 |
512a5f31408bbf36eae2af8deb420af42b56c88894452ee0a9971e4305d0d792
|
File details
Details for the file fasthook-1.0.1-py3-none-any.whl.
File metadata
- Download URL: fasthook-1.0.1-py3-none-any.whl
- Upload date:
- Size: 8.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cb1c5984b0a34c8be6cd2cb17a2d49bd7d973ef65d8faa0013b08f65c4586484
|
|
| MD5 |
483056418a56eb5e39403e043ceaa0a0
|
|
| BLAKE2b-256 |
50181c50915fb9a9ae2511a0bdde8f805cd7b993fb50c4b9361f03e02f7a017d
|