HTTP Headers
webhook.rodeo uses HTTP headers for tracking requests, routing webhooks, and verifying signatures. This reference covers all special headers you'll encounter.
Incoming headers
These are headers third party services send to webhook.rodeo when posting a webhook.
Standard headers
webhook.rodeo also captures all standard HTTP headers you send:
- Content-Type - Format of your payload (
application/json,application/xml, etc.) - User-Agent - Identifies the sending client
- Authorization - If your webhook sender includes auth headers
- Custom headers - Any service-specific headers (e.g.,
X-GitHub-Event)
All incoming headers are preserved and available in the event details for debugging.
Forwarding headers
When webhook.rodeo forwards events to your destination URL, we add special headers for tracking and include all original headers from the sender.
X-Rodeo-Request-Id
X-Rodeo-Request-Id: req_2gKp7vXm9nQ1rL3sT8wY
Purpose: Unique event identifier
This is the same requestId returned in the webhook response. Use it for:
- Idempotency checks (preventing duplicate processing)
- Tracking events across systems
- Debugging and support requests
Example use:
app.post('/webhooks', (req, res) => {
const requestId = req.headers['x-rodeo-request-id']
// Check if already processed
if (await db.hasProcessed(requestId)) {
return res.json({ status: 'duplicate' })
}
// Process webhook...
await processWebhook(req.body)
await db.markProcessed(requestId)
res.json({ status: 'processed' })
})
X-Rodeo-Webhook-Id
X-Rodeo-Webhook-Id: webhook_abc123def456
Purpose: Identifies which webhook received the event
Useful if you have multiple webhooks forwarding to the same URL and need to know which one triggered the event.
X-Rodeo-Attempt
X-Rodeo-Attempt: 2
Purpose: Delivery attempt number
Tells you which retry attempt this is:
1- First delivery attempt2- First retry (after 30s)3- Second retry (after 2m)4- Final retry (after 10m)
Example use:
app.post('/webhooks', (req, res) => {
const attempt = parseInt(req.headers['x-rodeo-attempt'])
if (attempt > 1) {
console.log(`⚠️ This is retry attempt #${attempt}`)
}
// Process webhook...
})
Original headers preserved
All headers from the original webhook sender are forwarded, except:
- Host - Changed to your destination host
- Connection - Removed (not meaningful for the forwarded request)
Everything else passes through unchanged, including:
- Content-Type
- User-Agent
- X-GitHub-Event, X-Stripe-Signature, etc. (service-specific headers)
Response headers
Headers you might see in webhook.rodeo responses.
Content-Type
Content-Type: application/json
webhook.rodeo always responds with JSON, so this is always application/json.
X-Request-Id
X-Request-Id: req_abc123
Same as the requestId in the JSON response body. Useful for logging and correlation.
Header examples
Receiving a webhook
When GitHub sends a webhook to webhook.rodeo:
POST /w/sarah/github-webhooks HTTP/1.1
Host: webhook.rodeo
Content-Type: application/json
X-GitHub-Event: push
X-GitHub-Delivery: 12345678-1234-1234-1234-123456789012
X-Hub-Signature-256: sha256=abc123...
User-Agent: GitHub-Hookshot/abc123
{
"ref": "refs/heads/main",
...
}
Forwarding to your endpoint
webhook.rodeo forwards with added headers:
POST /api/webhooks HTTP/1.1
Host: your-app.com
Content-Type: application/json
X-GitHub-Event: push
X-GitHub-Delivery: 12345678-1234-1234-1234-123456789012
X-Hub-Signature-256: sha256=abc123...
X-Rodeo-Request-Id: req_2gKp7vXm9nQ1rL3sT8wY
X-Rodeo-Webhook-Id: webhook_xyz789
X-Rodeo-Attempt: 1
User-Agent: GitHub-Hookshot/abc123
{
"ref": "refs/heads/main",
...
}
Notice how the original headers are preserved and webhook.rodeo's tracking headers are added.
Using headers for debugging
Tracing requests
Use X-Rodeo-Request-Id to trace a webhook through your entire system:
// In your webhook handler
const requestId = req.headers['x-rodeo-request-id']
// Log it
logger.info('Processing webhook', { requestId })
// Pass it to other services
await processPayment({
data: req.body,
requestId // Include for tracing
})
// Return it in responses
res.json({ status: 'ok', requestId })
Now you can search logs by requestId to see the full journey of a webhook from arrival to completion.
Handling retries
Check the attempt number to implement special retry logic:
const attempt = parseInt(req.headers['x-rodeo-attempt'])
if (attempt > 1) {
// This is a retry - maybe we should skip notifications
await process(req.body, { silent: true })
} else {
// First attempt - send notifications
await process(req.body, { notify: true })
}