Proxy headers
Hookman adds a set of x-hookman-* headers to every request it forwards. These are added to the outbound request — the one your application receives. The original sender never sees them.
Added headers
| Header | Example value | Description |
|---|---|---|
x-hookman-org | acme | The org slug |
x-hookman-project | payments | The project slug |
x-hookman-routing-method | rule | How the target was resolved: rule (a routing rule matched), switch (fell through to the active deployment), or fanout (this is a mirrored fan-out copy) |
x-hookman-rule-id | rule_01hw... | The ID of the rule that matched. Present only when routing-method is rule. |
x-hookman-rule-name | checkout-branch | The human-readable name of the matched rule. Present only when a rule matched. |
x-hookman-received | 2025-03-12T14:22:58.341Z | ISO 8601 timestamp when Hookman received the original request |
x-hookman-log-id | log_01hw... | The webhook log entry ID — use this to find the log in your dashboard |
x-hookman-delivery-id | a1b2c3... | Stable ID of this webhook delivery. Equal to the original webhook’s log ID and identical across automatic retries and manual replays — dedupe on it. Fan-out copies each get their own ID. |
x-hookman-attempt | 1 | 1 for the first delivery, 2 for the first automatic retry, and so on. Manual replays send 1. |
x-hookman-config-version | 7 | The route config version this delivery was routed with — useful for debugging stale config |
x-hookman-version | a1b2c3d | The proxy build (git SHA) that handled the request |
The original caller’s IP is preserved in the standard x-forwarded-for / cf-connecting-ip headers Cloudflare adds.
Replay-only headers
These are added only when the delivery is a replay (not a live webhook):
| Header | Example value | Description |
|---|---|---|
x-hookman-replay | true | Always true for replayed webhooks (absent otherwise) |
x-hookman-original-log-id | log_01hw... | Log ID of the original event being replayed |
Retries additionally send x-hookman-retry-attempt (the retry number, starting at 1).
x-hookman-delivery-id, x-hookman-attempt, x-hookman-replay, x-hookman-original-log-id and x-hookman-retry-attempt are owned by Hookman: any copies sent by the original caller are discarded and overwritten, so they can be trusted.
Deduplicating deliveries
const id = req.headers['x-hookman-delivery-id']if (await seen.has(id)) return res.sendStatus(200) // retry or replay of something already processedawait seen.add(id)Detecting replays in your application
// Express / Node.jsapp.post('/api/webhooks/stripe', (req, res) => { const isReplay = req.headers['x-hookman-replay'] === 'true'
if (isReplay) { // Skip sending confirmation emails, avoid double-charging, etc. console.log('Replay of log', req.headers['x-hookman-original-log-id']) }
// ... process webhook})Original headers are preserved
All headers from the original sender are forwarded unchanged. Hookman does not remove or modify any headers the sender included (e.g. stripe-signature, x-paddle-signature).
This means your existing HMAC signature verification continues to work without any changes.
// Stripe signature verification still worksconst event = stripe.webhooks.constructEvent( rawBody, req.headers['stripe-signature'], // ← forwarded unchanged by Hookman process.env.STRIPE_WEBHOOK_SECRET)import { Aside } from ‘@astrojs/starlight/components’