What Webhook Tester does
It answers one question: what is this service actually sending me? Then it gets out of the way. No account, no build step, no external database.
| Feature | What it means |
|---|---|
| Unique URLs |
Every bin gets an unguessable URL. Any method and any sub-path is captured, so
/hook/<id>/orders/created?x=1 lands in the same list.
|
| Live view | New requests appear over Server-Sent Events, without a page refresh. |
| Full request detail | Method, path, query parameters, headers, client IP and body. JSON is pretty-printed; binary bodies are shown as base64. |
| Custom responses |
Choose the status code, content type and body sent back, so you can watch a provider
retry a 500 or disable a webhook on 410.
|
| Persistent | Requests live in SQLite on a Docker volume and survive restarts. |
| Self-cleaning | Per-bin request limit, body size limit and automatic expiry of idle URLs. |
Quick start
One command. The image is published for linux/amd64 and linux/arm64.
docker run -d -p 8080:8080 -v webhook-tester-data:/data \
ghcr.io/webhooker-eu/webhook-tester
Open http://localhost:8080, click Create webhook URL, and send
something to it:
curl -X POST 'http://localhost:8080/hook/<your-id>' \
-H 'Content-Type: application/json' \
-d '{"hello": "world"}' Prefer to build the image yourself:
git clone https://github.com/webhooker-eu/webhook-tester.git
cd webhook-tester
docker compose up -d --build Receiving events from a real provider
Stripe, GitHub, Shopify and the rest can only call a public address, so a container on your
laptop is not reachable as it stands. Either run Webhook Tester on a small server behind TLS,
or open a tunnel (Cloudflare Tunnel, ngrok or similar) and give the provider the public
https://…/hook/<id> URL. The tool does not open a tunnel for you; it only
captures what arrives.
While you are there, keep an eye on the signature headers. They are stored unchanged, which
makes this the fastest way to see whether a provider sends Stripe-Signature,
X-Hub-Signature-256 or something of its own, and what the raw body looked like
when it was signed.
Configuration
Everything is an environment variable: pass it with docker run -e NAME=value, or
put it in a .env file next to docker-compose.yml.
| Variable | Default | What it controls |
|---|---|---|
MAX_BODY_BYTES | 1048576 | Largest stored body. Bigger ones are truncated and flagged. |
MAX_REQUESTS_PER_BIN | 200 | Requests kept per URL; the oldest are dropped first. |
BIN_TTL_HOURS | 168 | A URL expires after this long without traffic. 0 disables expiry. |
FORWARDED_ALLOW_IPS | 127.0.0.1 | Your reverse proxy's address, so client IPs come from X-Forwarded-For. |
DATABASE_PATH | /data/webhook-tester.db | SQLite file inside the container. |
HTTP API
Everything the UI does is available as JSON, with interactive docs at /docs. That
makes the tester usable from a test suite: create a bin, trigger your code, read the captured
request back.
| Method | Path | Description |
|---|---|---|
POST | /api/bins | Create a new capture URL. |
PUT | /api/bins/{id}/response | Set the status, content type and body returned to senders. |
GET | /api/bins/{id}/requests | List captured requests, newest first. |
GET | /api/bins/{id}/stream | Server-Sent Events stream of new requests. |
ANY | /hook/{id} | The capture endpoint itself, including any sub-path. |
When a request bin is not enough
A request bin is a mirror: it shows you traffic and forgets it. That is the right tool while you are reading payloads and writing a handler. It becomes the wrong one the moment an event has to reach your code reliably. A bin does not verify the provider's signature, does not retry when your service is down, and drops its oldest requests once the per-bin limit is hit.
Webhooker is the other half of that: one EU-hosted ingest URL per source, signatures checked before a payload is accepted, every event stored durably, six delivery attempts over about five hours, a dead-letter queue and one-click replay. The quick start takes four steps, and the free plan covers 10,000 events a month.
Frequently asked questions
How do I see what a webhook actually sends?
Create a URL in Webhook Tester and paste it into the provider's webhook settings. Every request that arrives is listed with its method, path, query parameters, headers, client IP and body; JSON is pretty-printed and the raw bytes are one click away. Nothing is parsed or rewritten on the way in, so what you see is what the provider sent.
Is there an open-source alternative to webhook.site or RequestBin?
Yes, that is what this is. It runs as a single Docker container with a SQLite file, has no accounts and keeps every payload on your own server, which matters when webhooks carry customer data, tokens or signature headers you cannot paste into a public website. RequestBin itself now lives inside Pipedream and asks you to sign up.
Can I receive webhooks on localhost?
Only through something public. Providers can reach a public address, so either run Webhook Tester on a server or expose your local container with a tunnel such as Cloudflare Tunnel or ngrok and give the provider the public /hook/<id> URL. Webhook Tester does not open a tunnel by itself.
Can the URL answer with an error, so I can test retries?
Yes. Open the "Replies to the sender" panel and pick any status from 200 to 599 with a content type and body. Answer 500 or 503 to watch how the provider backs off and retries, or 410 to see whether it disables the webhook after a permanent failure.
Does it verify webhook signatures?
No. It stores the body byte for byte and shows headers such as Stripe-Signature or X-Hub-Signature-256 unchanged, so you can compare them with what your own code computes. To send correctly signed test events to your app, use Webhook Mock Sender; to have signatures checked automatically before a payload is accepted, that is what the Webhooker gateway does.
Is it safe to put on the public internet?
There is no authentication: anyone who can open the instance can create URLs, and anyone who knows a URL can read its requests. The IDs are random and unguessable, but for a public deployment put the UI and /api/* behind your reverse proxy's auth and leave only /hook/* open.
Further reading
- Webhook.site and RequestBin alternatives compared
- How webhooks work: the request, header by header
- ngrok alternatives for getting webhooks onto your laptop
- The Webhooker ingest URL: limits and response codes
More open-source tools
Send a test message to a Discord webhook, and build the embed visually.
Webhook Mock SenderSend signed Stripe, GitHub and Shopify events to your own endpoint.
Everything we publish lives in the webhooker-eu GitHub organisation, and the full list with a short description of each is on the open-source tools page.