Skip to main content

Relay Rules & Forwarding

Automatically forward incoming webhook requests to your external endpoints with powerful filtering and transformation capabilities.


What are Relay Rules?

Relay rules define how hookVM forwards incoming webhook requests to your external URLs. Each rule specifies:

  • Destination URL: Where to forward the request
  • Retry Configuration: How many times to retry on failure
  • Filters: Which requests to forward (optional)
  • Transformations: How to modify the payload (optional)
  • Signature: Whether to add HMAC signature (optional)

Endpoint Detail Page

After creating an endpoint, you'll see the endpoint detail page with all configuration and monitoring information.

Endpoint Detail Page

Key Sections

Endpoint Configuration:

  • Source Type (e.g., Stripe)
  • Signature Verification status
  • Secret Key management

Statistics:

  • Total Requests received
  • Last Request timestamp
  • HTTP Method
  • Success Rate

Relay Rules:

  • List of configured relay rules
  • Create new relay rules
  • Manage existing rules

Webhook Requests:

  • Real-time list of incoming requests
  • Click any request to view details

Creating a Basic Relay Rule

Quick Setup (No Filters/Transformations)

Create Relay Rule

Configuration Fields

Rule Name

Give your relay rule a descriptive name.

Examples:

  • Relay to stage backend api
  • Forward to production server
  • Send to analytics service

Destination URL

The external URL where requests will be forwarded.

Format: https://yourwebsite.com/endpoint

Examples:

https://api.yourapp.com/webhooks/stripe
https://staging.yourapp.com/webhooks
https://analytics.yourapp.com/events

Retry Count

Number of times to retry if the destination fails to respond.

Default: 3
Range: 0-10
Recommended: 3-5 for production

Retry Behavior:

  • Retry on 5xx errors
  • Retry on network timeouts
  • Retry on connection failures
  • No retry on 4xx errors (client errors)

Retry Backoff (ms)

Time to wait between retry attempts in milliseconds.

Default: 1000ms (1 second)
Range: 100-60000ms
Recommended: 1000-5000ms

Backoff Strategy: Exponential

Attempt 1: Immediate
Attempt 2: After 1000ms
Attempt 3: After 2000ms
Attempt 4: After 4000ms

Add Signature

Include HMAC signature in the forwarded request for verification.

When Enabled:

  • Adds X-HookVM-Signature header
  • Uses HMAC-SHA256 algorithm
  • Allows destination to verify authenticity

Use Cases:

  • Verify requests came from hookVM
  • Prevent request tampering
  • Secure internal communications

Enable Rule

Start forwarding requests immediately.

Enabled: Requests are forwarded
Disabled: Rule exists but doesn't forward

Use Cases:

  • Temporarily pause forwarding
  • Test configuration before enabling
  • Maintenance windows

Advanced Configuration

For complex routing scenarios, use Advanced Configuration to add filters and transformations.

Advanced Configuration Button

Click "Advanced Configuration (Filters & Transformations)" to access:

  • Filter Rules
  • Transformation Scripts

Filter Rules

Control which requests are forwarded based on conditions.

Filter Rules Configuration

Enable Filtering

Toggle "Enable Filtering" to activate filter conditions.

When Disabled: All requests are forwarded
When Enabled: Only matching requests are forwarded

Match Type

Choose how multiple conditions are evaluated:

ALL (AND logic):

  • Request must match ALL conditions
  • Stricter filtering
  • Example: event_type = "invoice.updated" AND status = "paid"

ANY (OR logic):

  • Request matches if ANY condition is true
  • Broader filtering
  • Example: event_type = "invoice.created" OR event_type = "invoice.updated"

Filter Conditions

Define conditions using field paths, operators, and values.

Field Path

Specify the field to check using dot notation.

Syntax:

  • body.event.type - JSON field in request body
  • header.X-Event-Source - HTTP header
  • query.source - Query parameter
  • method - HTTP method (POST, GET, etc.)

Examples:

body.event.type
body.data.amount
header.X-Stripe-Event
query.source
method

Operators

Equals: Exact match

body.event.type Equals invoice.updated

Contains: Partial match

body.customer.email Contains @example.com

Greater Than / Less Than: Numeric comparison

body.data.amount GreaterThan 10000

Exists: Check if field exists

body.metadata.order_id Exists

Value

The value to compare against.

Examples:

invoice.updated
paid
100
@example.com

Multiple Conditions

Click "+ Add Condition" to add more filter rules.

Example: Filter High-Value Paid Invoices

Condition 1: body.event.type Equals invoice.updated
Condition 2: body.data.status Equals paid
Condition 3: body.data.amount GreaterThan 10000
Match Type: ALL

Example Field Paths

The interface shows helpful examples:

  • body.event.type - JSON field in request body
  • header.X-Event-Source - HTTP header
  • query.source - Query parameter
  • method - HTTP method (POST, GET, etc.)

Transformation Scripts

Modify webhook payloads before forwarding using JavaScript.

Transformation Script

Enable Transformation

Toggle "Transformation Script" to activate payload modification.

JavaScript Editor

Write JavaScript code to transform the webhook object.

Available Variables:

// webhook object structure:
// {
// method: string,
// headers: object,
// queryParams: object,
// body: object (if JSON) or string
// }

Return Value: Modified webhook object

Transformation Examples

Add Custom Header

function transform(webhook) {
// Add a custom header
webhook.headers['X-Custom-Header'] = 'Transformed';
return webhook;
}

Modify Body

function transform(webhook) {
// Example: Modify body
if (webhook.body && typeof webhook.body === 'object') {
webhook.body.transformed = true;
webhook.body.timestamp = new Date().toISOString();
}
return webhook;
}

Simplify Stripe Payload

function transform(webhook) {
if (webhook.body && webhook.body.type === 'payment_intent.succeeded') {
// Simplify Stripe payload
const original = webhook.body.data.object;
webhook.body = {
event: 'payment_success',
payment_id: original.id,
amount_usd: original.amount / 100,
customer_id: original.customer,
metadata: original.metadata
};
}
return webhook;
}

Extract Nested Data

function transform(webhook) {
// Extract nested data to top level
if (webhook.body && webhook.body.data) {
webhook.body = {
...webhook.body.data.object,
event_type: webhook.body.type
};
}
return webhook;
}

Test Transformation

Before saving, test your transformation script:

  1. Sample Payload (JSON): Enter a sample webhook payload
  2. Run Test: Click "Run Test" button
  3. Result: See the transformed output

Example Test:

Input:

{
"event": "user.created",
"data": {
"id": "123",
"email": "test@example.com"
}
}

Output (after transformation):

{
"event": "user.created",
"data": {
"id": "123",
"email": "test@example.com",
"transformed": true,
"timestamp": "2025-12-27T14:58:01.042Z"
}
}

Complete Workflow

1. Create Endpoint

Create an endpoint to receive webhooks from external sources.

2. Configure Basic Relay Rule

Set up destination URL, retry configuration, and enable the rule.

3. Add Filters (Optional)

Define conditions to selectively forward requests.

4. Add Transformations (Optional)

Modify payloads before forwarding.

5. Test & Monitor

Send test requests and monitor in the Requests section.


Common Use Cases

Fan-Out to Multiple Destinations

Create multiple relay rules for the same endpoint:

Rule 1: Backend API

Name: Forward to Backend
Destination: https://api.yourapp.com/webhooks
Retry Count: 3
Filters: None

Rule 2: Analytics

Name: Send to Analytics
Destination: https://analytics.yourapp.com/events
Retry Count: 5
Filters: body.event.type Contains "payment"

Rule 3: Notifications

Name: Trigger Notifications
Destination: https://notifications.yourapp.com/webhook
Retry Count: 3
Filters: body.data.amount GreaterThan 10000

Conditional Routing

Route different event types to different destinations:

High-Value Payments

Destination: https://api.yourapp.com/high-value-payments
Filters:
- body.event.type Equals payment_intent.succeeded
- body.data.amount GreaterThan 100000

Regular Payments

Destination: https://api.yourapp.com/payments
Filters:
- body.event.type Equals payment_intent.succeeded
- body.data.amount LessThan 100000

Payload Simplification

Transform complex provider payloads into simple formats:

Stripe to Simple Format

function transform(webhook) {
if (webhook.body.type === 'payment_intent.succeeded') {
const payment = webhook.body.data.object;
webhook.body = {
event: 'payment_success',
id: payment.id,
amount: payment.amount / 100,
currency: payment.currency,
customer: payment.customer
};
}
return webhook;
}

Best Practices

Retry Configuration

Production:

  • Retry Count: 3-5
  • Retry Backoff: 1000-5000ms
  • Enable signature verification

Development:

  • Retry Count: 1-2
  • Retry Backoff: 500-1000ms
  • Test without retries first

Filtering

Do:

  • Use specific conditions
  • Test filters before enabling
  • Document filter logic
  • Use AND logic for strict filtering

Don't:

  • Create overly complex filters
  • Use too many OR conditions
  • Filter on unreliable fields

Transformations

Do:

  • Test transformations thoroughly
  • Keep transformations simple
  • Add error handling
  • Document transformation logic
  • Use the test feature

Don't:

  • Make transformations too complex
  • Modify critical fields
  • Remove important data
  • Use external API calls

Security

Enable Signature: For production relay rules
Use HTTPS: Always use HTTPS destinations
Validate Destination: Ensure destination URL is correct
Monitor Failures: Check for relay failures regularly


Monitoring & Debugging

View Relay Attempts

In the endpoint detail page:

  1. Click on any request in "Webhook Requests"
  2. View relay attempts and responses
  3. Check success/failure status
  4. Review error messages

Common Issues

Relay Failing:

  • Check destination URL is correct
  • Verify destination is accessible
  • Check retry configuration
  • Review error messages

Filters Not Working:

  • Verify field paths are correct
  • Check operator logic
  • Test with sample payloads
  • Review match type (ALL vs ANY)

Transformation Errors:

  • Test transformation script
  • Check JavaScript syntax
  • Verify webhook object structure
  • Review error logs

Next Steps


Ready to forward webhooks? Create your first relay rule and start routing requests! 🚀