Hookbase
LoginGet Started Free
Back to Blog
Guides

Webhook Payload Transformation: A Complete Guide

Learn how to transform webhook payloads on the fly using Hookbase's powerful transformation engine. Support for JSONata, JavaScript, Liquid templates, and XSLT.

Hookbase Team
January 18, 2026
10 min read

Why Transform Webhook Payloads?

When integrating webhooks between services, the payload format rarely matches what your destination expects. A Stripe webhook doesn't look like a Slack message. A GitHub event isn't formatted for your CRM. Instead of writing backend code to transform every payload, Hookbase lets you transform webhooks on the fly.

Four Powerful Transform Engines

Hookbase supports four transformation languages, each suited for different use cases.

1. JSONata - Query and Transform JSON

JSONata is a lightweight query and transformation language for JSON data. It's perfect for restructuring payloads without writing code.

// Extract and reshape Stripe payment data
{
  "customer": data.object.customer,
  "amount": data.object.amount / 100,
  "currency": $uppercase(data.object.currency),
  "status": type = "payment_intent.succeeded" ? "paid" : "pending"
}

Best for: Simple restructuring, field extraction, conditional logic.

2. JavaScript - Full Programmatic Control

When you need loops, complex logic, or custom functions, JavaScript gives you full control in a secure sandbox.

// Flatten nested objects for analytics
function flatten(obj, prefix = '') {
  return Object.keys(obj).reduce((acc, key) => {
    const pre = prefix ? prefix + '.' : '';
    if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) {
      Object.assign(acc, flatten(obj[key], pre + key));
    } else {
      acc[pre + key] = obj[key];
    }
    return acc;
  }, {});
}
return flatten(payload);

Best for: Complex logic, loops, string manipulation, calculations.

3. Liquid - Template-Based Transforms

Liquid templates are ideal when you're generating formatted text or HTML, like Slack messages or email bodies.

🔔 *New Order Received*

*Order ID:* {{ payload.id }}
*Customer:* {{ payload.customer.email }}
*Total:* {{ payload.total | divided_by: 100 | prepend: "$" }}

*Items:*
{% for item in payload.items %}
  - {{ item.name }} (x{{ item.quantity }})
{% endfor %}

Best for: Notification messages, formatted text, email templates.

4. XSLT - XML Transformations

For legacy systems that speak XML, XSLT transforms let you convert between JSON and XML or transform XML payloads.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <order>
      <id><xsl:value-of select="//order_id"/></id>
      <total><xsl:value-of select="//amount"/></total>
    </order>
  </xsl:template>
</xsl:stylesheet>

Best for: XML integrations, SOAP services, enterprise systems.

Real-World Examples

Stripe to Slack

Transform a Stripe payment webhook into a Slack notification:

{
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "💰 *Payment Received*\n" &
          "*Amount:* $" & (data.object.amount / 100) & "\n" &
          "*Customer:* " & data.object.customer_email
      }
    }
  ]
}

GitHub PR to Discord

Notify your team about pull requests:

{
  "content": "📝 **" & action & "** PR #" & pull_request.number,
  "embeds": [{
    "title": pull_request.title,
    "url": pull_request.html_url,
    "author": { "name": pull_request.user.login },
    "color": action = "opened" ? 5763719 : 15105570
  }]
}

Mask Sensitive Data

Remove or mask sensitive fields before forwarding:

const sensitiveFields = ['password', 'ssn', 'credit_card', 'api_key'];

function maskSensitive(obj) {
  if (typeof obj !== 'object' || obj === null) return obj;

  return Object.keys(obj).reduce((acc, key) => {
    if (sensitiveFields.includes(key.toLowerCase())) {
      acc[key] = '***REDACTED***';
    } else if (typeof obj[key] === 'object') {
      acc[key] = maskSensitive(obj[key]);
    } else {
      acc[key] = obj[key];
    }
    return acc;
  }, Array.isArray(obj) ? [] : {});
}

return maskSensitive(payload);

Built-In Template Library

Don't start from scratch. Hookbase includes 15+ pre-built templates for common integrations:

  • Stripe → Slack: Payment notifications
  • GitHub → Discord: PR and issue alerts
  • Shopify → Inventory systems: Order processing
  • Generic → Any: Flatten objects, mask fields, add metadata

Security Built In

Transforms run in a secure sandbox with:

  • 5-second timeout: Prevents infinite loops
  • No network access: JavaScript can't make HTTP requests
  • No file system: Templates can't read or write files
  • Safe built-ins only: Math, Date, JSON:nothing dangerous

Context Variables

Every transform has access to useful context:

| Variable | Description | |----------|-------------| | payload | The webhook payload (parsed JSON/XML) | | headers | Original request headers | | eventId | Unique event identifier | | sourceId | Source that received the webhook |

Test Before You Deploy

Use the transform tester to validate your code before saving:

  1. Paste a sample payload
  2. Write your transform
  3. See the output instantly
  4. Fix errors before they affect production

Getting Started

  1. Create a transform in your Hookbase dashboard
  2. Choose your engine (JSONata for most cases)
  3. Write and test your transformation code
  4. Attach to a route to start transforming webhooks

Transforms are available on all paid plans. Start transforming your webhooks today.

webhookstransformationjsonatajavascriptintegration

Related Articles

Product Update

Test Real Webhooks in CI With Three Lines of YAML

The new hookbase/setup-tunnel GitHub Action exposes a localhost port via a public Hookbase tunnel during CI runs. Receive real webhooks from Stripe, GitHub, Shopify, or any provider against ephemeral test environments — without managing tunnel lifecycle by hand.

Tutorial

Shopify Webhook Signature Verification, Explained

Shopify HMAC verification trips up almost every first-time integrator. Here is exactly how the signature is computed, what goes wrong, and a working implementation in Node, Python, Go, and Ruby.

Reference

Webhook Retries: What Every Provider Does Differently

Stripe retries for 3 days. GitHub gives up after one failure. Shopify retries 19 times. Knowing the rules for each provider is the difference between losing events and not. A reference table plus what it means for your handler.

Ready to Try Hookbase?

Start receiving, transforming, and routing webhooks in minutes.

Get Started Free
Hookbase

Reliable webhook infrastructure for modern teams. Built on Cloudflare's global edge network.

Product

  • Features
  • Pricing
  • Use Cases
  • Integrations
  • ngrok Alternative

Resources

  • Documentation
  • API Reference
  • CLI Guide
  • Blog
  • FAQ

Free Tools

  • All Tools
  • Webhook Bin
  • HMAC Calculator
  • JSONata Playground
  • Cron Builder
  • Payload Formatter
  • Local Testing

Legal

  • Privacy Policy
  • Terms of Service
  • Contact
  • Status

© 2026 Hookbase. All rights reserved.