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 attempt
  • 2 - 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 })
}

Was this page helpful?