Test Postmark webhooks without deploying
Capture bounce, delivery and inbound events from Postmark, which does not sign webhooks at all.
Get a URL that accepts the webhook#
A capture URL takes any method, any body, and records exactly what arrived: method, headers, query string, body and source IP. You do not need an account to make one, and an anonymous URL is deleted after 24 hours.
curl -X POST https://mocklane.com/api/v1/anon/endpoints \
-H "Content-Type: application/json" -d '{}'
# The response carries a capture URL of the form:
# https://mocklane.com/h/<endpoint-id>Paste that URL into Postmark at Postmark server, Settings, Webhooks, then trigger something. Events worth starting with:
DeliveryBounceSpamComplaintOpenInbound
How Postmark authenticates its requests#
- Postmark states plainly that it does not currently support HMAC webhook signature verification. There is no signature header to check, so every tutorial that tells you to verify one is wrong about Postmark.
- What it offers instead is credentials in the URL: https://user:pass@your-app.example.com/webhooks/postmark, over HTTPS so they are encrypted in transit.
- The second layer is a firewall rule restricting the endpoint to Postmark's published webhook IP ranges. The originating address can change between retry attempts, so allow the whole published range rather than a single address.
- X-PM-Retries-Remaining and X-PM-Webhook-Trace-Id are sent on deliveries, but they are operational metadata, not authentication. The trace id stays stable across retries of the same event, which makes it useful for deduplication.
A capture URL is useful here for the same reason: it shows you exactly which headers do arrive, so you can see for yourself what is and is not available to authenticate on.
What catches people out#
- Because there is no signature, anyone who learns the URL can post to it. Treat the URL itself as the secret and rotate it if it leaks.
- Credentials in a URL end up in logs and referrer headers more easily than a header does, so keep the endpoint narrow and the account low-privilege.
- Validate the payload shape in your handler as a cheap extra check, since you have no cryptographic guarantee.
Replay it until your handler is right#
A captured request can be re-sent to your own endpoint, with the body or headers edited first. That turns a bug that needed a real Postmark event into something you can reproduce on demand, which matters most for events that are awkward to trigger twice.
Assert on it in CI#
A scenario chains the steps into one run that passes or fails, so a change that breaks your Postmark handling fails the build rather than reaching production.
steps:
- type: send_webhook
body: { event: "Delivery" }
- type: wait_for_webhook
timeout_seconds: 30
assert:
- status_code equals 200Triggered from CI with an API token. See the scenarios documentation for the full step list.
Signature details checked against Postmark’s documentation on 22 October 2026. Schemes change: if this page and their docs disagree, believe theirs and tell us.