Put your email in the URL. Point a webhook at it. Every header, every byte of body, every superglobal shows up as an email. Done. Go do the next thing.
https://webhooks.dixon.cx/you%40example.com
Yes the @ becomes %40. Yes that's the whole trick. Add /github, /json, etc. on the end for the fancy parsers — more on that below, if you scroll that far.
The third one is just "wait for an email", which you were going to do anyway.
@ → %40. The box above already did it for you. Ok moving on.curl -X POST https://webhooks.dixon.cx/you%40example.com \
-d '{"test": "hello, is this thing on"}'
(the email will arrive before you've alt-tabbed back. probably. depends on your mail server. anyway.)
Any method, any content type. GET, POST, PUT, PATCH, DELETE, something you made up. JSON, form data, multipart, XML, plain text, a string of emoji. It all gets forwarded.
# JSON curl -X POST https://webhooks.dixon.cx/you%40example.com \ -H "Content-Type: application/json" \ -d '{"event": "user.created", "user_id": 12345}' # GET with query string (yes, this works too) curl "https://webhooks.dixon.cx/you%40example.com?event=test&id=123"
fetch('https://webhooks.dixon.cx/' + encodeURIComponent('you@example.com'), { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ event: 'order.completed', order_id: 'ORD-789', total: 99.99 }) });
import requests from urllib.parse import quote requests.post( f'https://webhooks.dixon.cx/{quote("you@example.com")}', json={'event': 'payment.received', 'amount': 250.00}, headers={'X-Custom-Header': 'MyValue'}, )
Pro tip you'll ignore and then come back for: use plus addressing. you+stripe%40example.com, you+github%40example.com. Now your inbox filters do the sorting so you don't have to.
Add one word to the end of the URL and the email stops being a wall of raw JSON and starts being something you can actually read at 3am. Parser doesn't understand the payload? It falls back to the raw format. Nothing gets lost.
/githubPush, pull request, issue and release events get their own layout with commits, authors, branches and links. Everything else still renders, just less fancy. Subjects like 📤 GitHub push - you/repo.
/grafanaGrafana and Prometheus Alertmanager alerts. Firing, resolved, labels, annotations. Finally know which thing is on fire.
/jsonAny JSON at all, rendered as tables. Nested objects get split out into their own tables with path-based titles so you can find data.items[3].sku without squinting.
/wxinteractWebex Interact SMS events. Inbound messages, delivery receipts, the lot, with the event type in the subject line.
https://webhooks.dixon.cx/you%40example.com/githubapplication/jsonOne HTML email per request. Gmail-safe styling. All of the following, every time, whether you asked for it or not:
{
"ok": true,
"message": "Webhook received and forwarded to you@example.com",
"forwarded_to": "you@example.com",
"parser": "default",
"subject": "‼️ Webhook Request Received - 2026-09-11 17:15:42",
"received_at": "2026-09-11T17:15:42+00:00",
"request": { "method": "POST", "content_type": "application/json", "ip": "203.0.113.7", "headers": 9, "body_bytes": 40 },
"data": {
"query": { "src": "curl" },
"form": {},
"json": { "event": "user.created", "user_id": 12345 },
"files": []
}
}
JSON bodies get decoded and echoed back under data.json, so you can eyeball what the server actually understood. Form fields land in form, query string in query. No print_r in sight.
Any 200 is enough for most services to mark the delivery as "succeeded" and stop retrying. Which is the point.
Anyone with the URL can email you. There's no auth. There's no secret. It's your email address in a URL. Use it for debugging and testing. Do not point production payment data at it. Don't make me put a bigger warning here.
htmlspecialchars() before it hits the email, so a malicious payload renders as text, not as a thing.{"ok": false, "error": "invalid_email", ...} with a hint about %40. Validated with PHP's FILTER_VALIDATE_EMAIL. Boring, correct.