Hookbase
Docs
GuideAPI ReferenceIntegrationsUse CasesCLIMCP
Getting StartedSDK ReferencePortal ComponentsAPI Reference
Get Started

Getting Started

IntroductionQuick StartBest PracticesPipeline Architecture

Core Concepts

SourcesDestinationsRoutes

Advanced Features

TransformsAI TransformsFiltersSchemasDeduplicationCustom DomainsTunnelsCron JobsScheduled Sends

Enterprise Security

OverviewCircuit BreakerFailover DestinationsIP FilteringStatic IP DeliveryNotification ChannelsObservability ExportField EncryptionAudit Logs

Kubernetes

Operator GuideCRD ReferenceHelm Chart

Operations

Plans & LimitsProduction ReadinessTroubleshootingTestingComparison
DocsReceiveGuideTransforms

Transforms

Transforms modify webhook payloads using JavaScript before delivery.

Overview

Transforms modify webhook payloads before delivery using one of four supported languages. Use them to:

  • Reshape data to match your application's format
  • Extract specific fields
  • Add computed values
  • Convert between data formats (JSON, XML, text)
  • Mask sensitive data

Transform Types

Hookbase supports four transform engines:

TypeLanguageBest For
jsonataJSONataDeclarative JSON-to-JSON mapping (default)
javascriptJavaScriptComplex logic, conditionals, string manipulation
liquidLiquidTemplate-based output, generating text/HTML
xsltXSLTXML-to-XML or XML-to-JSON transformations

Creating a Transform

Fields

FieldDescription
nameHuman-readable name
codeTransform code
typeTransform type: jsonata (default), javascript, liquid, xslt
inputFormatExpected input format: json (default), xml, text
outputFormatOutput format: json (default), xml, text

JSONata (Default)

JSONata is a lightweight query and transformation language for JSON. It's the recommended approach for straightforward mappings.

{
  "eventType": action,
  "repository": repository.full_name,
  "sender": sender.login,
  "timestamp": $now()
}

See the JSONata documentation for the full expression reference.

JavaScript

JavaScript transforms receive the payload as an argument and return the transformed result.

function transform(payload) {
  return {
    // Your transformed data
  };
}

Liquid

Liquid templates are useful for generating formatted text or HTML output.

New event from 
Action: 
By: 

XSLT

XSLT transforms are designed for XML payloads. Set inputFormat: "xml" when using XSLT.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <event>
      <type><xsl:value-of select="/webhook/action"/></type>
      <source><xsl:value-of select="/webhook/repository/name"/></source>
    </event>
  </xsl:template>
</xsl:stylesheet>

Code Validation

When creating or updating a transform, Hookbase validates the code:

  • JSONata: Parses the expression and reports syntax errors
  • JavaScript: Checks for syntax errors and unsafe operations (no eval, Function, require)
  • Liquid: Validates template syntax
  • XSLT: Validates XML and stylesheet structure

Examples

Extract Specific Fields

function transform(payload) {
  return {
    eventType: payload.action,
    repository: payload.repository?.full_name,
    sender: payload.sender?.login,
    timestamp: new Date().toISOString()
  };
}

Format for Slack

function transform(payload) {
  return {
    text: `New event from ${payload.repository?.full_name}`,
    blocks: [
      {
        type: "section",
        text: {
          type: "mrkdwn",
          text: `*${payload.action}* by ${payload.sender?.login}`
        }
      }
    ]
  };
}

Add Metadata

function transform(payload) {
  return {
    ...payload,
    _meta: {
      processedAt: new Date().toISOString(),
      source: "hookbase",
      version: "1.0"
    }
  };
}

Filter and Reshape Array

function transform(payload) {
  const items = payload.items || [];
 
  return {
    count: items.length,
    items: items
      .filter(item => item.status === "active")
      .map(item => ({
        id: item.id,
        name: item.name
      }))
  };
}

Mask Sensitive Data

function transform(payload) {
  return {
    ...payload,
    email: payload.email?.replace(/(.{2}).*(@.*)/, "$1***$2"),
    creditCard: payload.creditCard ? "****" + payload.creditCard.slice(-4) : null
  };
}

Testing Transforms

Use the Testing page to verify your transform works correctly:

  1. Navigate to Testing in the sidebar
  2. Select your source and route
  3. Enter a sample payload
  4. Click Send Test
  5. View the transformed output

Or use the Transforms page directly:

  1. Navigate to Transforms in the sidebar
  2. Click on a transform to edit
  3. Enter a sample payload in the test section
  4. Click Test Transform
  5. View the result

API Usage

Create Transform

# JavaScript transform
curl -X POST https://api.hookbase.app/api/transforms \
  -H "Authorization: Bearer whr_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "GitHub to Slack",
    "type": "javascript",
    "code": "function transform(payload) { return { text: payload.action }; }"
  }'
 
# JSONata transform (default type)
curl -X POST https://api.hookbase.app/api/transforms \
  -H "Authorization: Bearer whr_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Extract Fields",
    "type": "jsonata",
    "code": "{ \"event\": action, \"repo\": repository.full_name }"
  }'

List Transforms

curl https://api.hookbase.app/api/transforms \
  -H "Authorization: Bearer whr_your_api_key"

Update Transform

curl -X PATCH https://api.hookbase.app/api/transforms/{transformId} \
  -H "Authorization: Bearer whr_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "function transform(payload) { return { text: payload.action, repo: payload.repository.name }; }"
  }'

Delete Transform

curl -X DELETE https://api.hookbase.app/api/transforms/{transformId} \
  -H "Authorization: Bearer whr_your_api_key"

Best Practices

  1. Keep it simple: Transforms run on every webhook; keep code efficient

  2. Handle missing data: Use optional chaining (?.) and default values

  3. Test thoroughly: Test with various payload shapes before deploying

  4. Don't make external calls: Transforms should be pure functions; no HTTP requests

  5. Return valid JSON: Ensure your transform returns serializable data

  6. Version your transforms: Include version info in names or metadata

Limitations

  • Execution time: Transforms must complete within 50ms
  • Memory: Limited to 128KB of memory
  • No external access: Cannot make HTTP requests or access external resources
  • No persistent state: Each execution is independent

Error Handling

If a transform fails:

  • The original payload is used (no transformation)
  • An error is logged
  • Delivery continues to destinations

To debug transform errors:

  1. Check the Event Debugger for error messages
  2. Test with the exact payload that caused the error
  3. Add defensive coding (null checks, try/catch)
function transform(payload) {
  try {
    return {
      data: payload.nested?.deeply?.value || "default"
    };
  } catch (error) {
    // Return original on error
    return payload;
  }
}

See Also

  • Transforms API — Full API reference
  • Filters — Conditional event filtering
  • Schemas — Validate payloads before transforms
  • Best Practices — Tips for production transforms
PreviousRoutesNextAI Transforms

On this page

OverviewTransform TypesCreating a TransformFieldsJSONata (Default)JavaScriptLiquidXSLTCode ValidationExamplesExtract Specific FieldsFormat for SlackAdd MetadataFilter and Reshape ArrayMask Sensitive DataTesting TransformsAPI UsageCreate TransformList TransformsUpdate TransformDelete TransformBest PracticesLimitationsError HandlingSee Also