Event payloads

Every node in the pipeline receives a specific context object depending on the scenario. This page is the exhaustive reference for every payload shape, every template variable, and how data flows between nodes.

How data flows

When an external service sends a webhook to HostWebhook, the data goes through a pipeline of nodes. Each node receives the data in a different shape depending on the scenario:

Webhook arrives | v Webhook (primary delivery to targetUrl) | +---> Chain (next webhook receives wrapped payload) +---> Additional targets (optional payload transform) +---> HTTP Action (makes an HTTP request) | +---> Output webhooks (receive the HTTP response) +---> Transform node (reshapes payload, routes to webhooks) +---> Filter node (evaluates rules, routes matching events) +---> Router (forwards to webhook or URL) +---> Email Action (sends email via template) +---> Alert (notifies on failure thresholds)
Each arrow in the diagram above produces a different context object. The sections below document the exact shape for every scenario.

Original webhook payload

When a webhook arrives at a webhook's ingress URL, the raw JSON body is the original payload. This is the unmodified data from the external service (Stripe, GitHub, your app, etc.).

jsonExample — Stripe payment event
{
  "id": "evt_1abc",
  "type": "payment_intent.succeeded",
  "data": {
    "object": {
      "id": "pi_xyz",
      "amount": 5000,
      "currency": "usd",
      "customer": "cus_123"
    }
  }
}

The primary webhook delivery sends this payload as-is to the target URL (unless a payload transform is configured on the webhook). All downstream nodes reference this as the payload object.


Delivery context (payload transforms)

When a payload transform is configured on a webhook or an additional target, the transform template has access to a richer context object — not just the payload.

jsonFull delivery context
{
  "payload": {
    "type": "payment_intent.succeeded",
    "data": { "object": { "amount": 5000 } }
  },
  "headers": {
    "content-type": "application/json",
    "stripe-signature": "t=123,v1=abc..."
  },
  "meta": {
    "eventId": "6650a1b2c3d4e5f6a7b8c9d0",
    "webhookId": "6650a1b2c3d4e5f6a7b8c9d1",
    "attempt": "1",
    "receivedAt": "2024-06-01T12:00:00.000Z"
  }
}
ObjectDescriptionTemplate example
payloadThe parsed JSON body of the incoming webhook{{payload.type}}
headersInbound request headers (lowercase keys){{headers.content-type}}
meta.eventIdThe HostWebhook event ID{{meta.eventId}}
meta.webhookIdThe webhook that received the event{{meta.webhookId}}
meta.attemptCurrent delivery attempt number (as string){{meta.attempt}}
meta.receivedAtISO 8601 timestamp when the event arrived{{meta.receivedAt}}

Additional target with forwardResponse

When an additional target has forwardResponse: true, the primary delivery's response is available as an additional response object in the transform context.

jsonAdditional target context with forwardResponse
{
  "payload": {
    "type": "order.created",
    "orderId": "ord_123"
  },
  "headers": { "content-type": "application/json" },
  "meta": {
    "eventId": "...",
    "webhookId": "...",
    "attempt": "1",
    "receivedAt": "2024-06-01T12:00:00.000Z"
  },
  "response": {
    "status": 200,
    "body": { "processed": true, "internalId": "int_456" },
    "raw": "{"processed":true,"internalId":"int_456"}"
  }
}
FieldDescription
response.statusHTTP status code from the primary delivery
response.bodyParsed JSON body (or empty object if not JSON)
response.rawRaw response string
Use this to forward the primary server's response to a third-party service. For example: {{response.body.internalId}} in a transform to include the primary server's ID in a Discord notification.

Chain payload

When a webhook has chained webhooks, the next webhook in the chain receives a wrapped payload — not the original webhook body. This lets you access both the original data and the previous step's response.

Successful delivery (step 2+)

jsonChain payload — success
{
  "original": {
    "type": "order.created",
    "orderId": "ord_123"
  },
  "previous": {
    "processed": true,
    "internalId": "int_456"
  },
  "response": {
    "status": 200,
    "body": { "processed": true, "internalId": "int_456" },
    "raw": "{"processed":true,"internalId":"int_456"}",
    "truncated": false,
    "originalSize": 52
  }
}
FieldDescription
originalThe very first payload in the chain (root webhook body)
previousParsed response body from the previous step (JSON or string)
response.statusHTTP status code from the previous step
response.bodyParsed JSON response (or empty object)
response.rawRaw response string
response.truncatedtrue if the response was truncated due to plan limits
response.originalSizeOriginal byte count before truncation (only if truncated)

Chain with forwardResponse

When a chain connection has forwardResponse: true, the HTTP body delivered to the chained webhook's target URL is the previous step's response.bodynot the full wrapped object. Your server receives the previous server's response directly as the request body.

The full wrapped payload (with original, previous, response) is still accessible via the chain headers described below.

Chain headers

In addition to the wrapped payload, HostWebhook adds special headers to every chain delivery:

HeaderValue
X-HostWebhook-Chain-StepCurrent step number (e.g., "1", "2", "3")
X-HostWebhook-Chain-OriginalBase64-encoded JSON of the original root payload
X-HostWebhook-Chain-PreviousBase64-encoded JSON of the previous step's response

Failed delivery (continueOnFailure)

When a chain connection has continueOnFailure: true and the previous step's delivery failed, the next webhook still receives the chain payload — but previous contains an error object instead of the response:

jsonChain payload — failed delivery
{
  "original": {
    "type": "order.created",
    "orderId": "ord_123"
  },
  "previous": {
    "error": true,
    "message": "Connection refused"
  }
}
When the previous delivery failed, there is no response object — only the error in previous. Check for previous.error === true in your server to handle failure scenarios.

HTTP Action context

HTTP Actions receive a context object that varies depending on the trigger scenario. The context is used to interpolate template variables in the URL, headers, and body of the HTTP request.

Scenario 1 — Direct webhook (no chain)

The most common scenario: a webhook arrives at a webhook, the primary delivery succeeds, and the connected HTTP Action fires.

jsonHTTP Action context — direct webhook
{
  "payload": {
    "type": "order.created",
    "orderId": "ord_123",
    "customer": { "email": "[email protected]" }
  },
  "response": {
    "status": 200,
    "body": { "processed": true },
    "raw": "{"processed":true}"
  }
}
FieldDescription
payloadThe original webhook payload (raw body from external service)
response.statusHTTP status code from the webhook's primary delivery
response.bodyParsed JSON response from the primary target URL
response.rawRaw response string from the primary target URL
jsonTemplate usage example
// HTTP Action URL:
https://api.crm.com/customers/{{payload.customer.email}}/orders

// HTTP Action body:
{
  "orderId": "{{payload.orderId}}",
  "wasProcessed": "{{response.body.processed}}",
  "serverStatus": "{{response.status}}"
}

Scenario 2 — Delivery failed (triggerOn: always)

If the HTTP Action is configured with triggerOn: always, it fires even when the primary delivery fails. In this case, there is no response object:

jsonHTTP Action context — delivery failed
{
  "payload": {
    "type": "order.created",
    "orderId": "ord_123"
  }
}
Use null coalescing when referencing response fields in templates shared between success/failure scenarios: {{response.status ?? 0}}

Scenario 3 — Chain event (step 2+)

When an HTTP Action is connected to a webhook that is part of a chain, it receives the chain context as an additional chain object:

jsonHTTP Action context — chain event
{
  "payload": {
    "type": "order.created",
    "orderId": "ord_123"
  },
  "response": {
    "status": 200,
    "body": { "enriched": true, "trackingNumber": "TRK-789" },
    "raw": "{"enriched":true,"trackingNumber":"TRK-789"}"
  },
  "chain": {
    "step": 2,
    "original": {
      "type": "order.created",
      "orderId": "ord_123"
    },
    "previous": {
      "enriched": true,
      "trackingNumber": "TRK-789"
    },
    "priorResponse": {
      "status": 200,
      "body": { "enriched": true, "trackingNumber": "TRK-789" },
      "raw": "..."
    }
  }
}
FieldDescription
chain.stepCurrent chain step number
chain.originalThe root webhook payload (step 0)
chain.previousParsed response from the previous step
chain.priorResponseFull response object from the previous step (status, body, raw)
In a chain scenario, payload always refers to the original webhook payload — not the chain wrapper. Use {{chain.previous.field}} to access the prior step's response.

Scenario 4 — Test execution (dashboard)

When you use the Run Test button on the HTTP Action detail page, the context contains only what you provide:

jsonTest execution context
{
  "payload": {
    "whatever": "you type in the textarea"
  }
}

No response or chain objects — only the payload you provide. Useful for testing template interpolation.


HTTP Action output (downstream webhooks)

When an HTTP Action has output webhooks configured, the response from the HTTP request is forwarded to those webhooks as a new event. The downstream webhook receives a structured payload:

jsonDownstream webhook payload (from HTTP Action)
{
  "original": {
    "type": "order.created",
    "orderId": "ord_123"
  },
  "httpAction": {
    "name": "Fetch Order Details",
    "method": "GET",
    "url": "https://api.legacy.com/orders/ord_123"
  },
  "httpResponse": {
    "statusCode": 200,
    "body": {
      "orderTotal": 99.99,
      "items": [
        { "sku": "ITEM-1", "qty": 2 }
      ]
    },
    "raw": "{"orderTotal":99.99,"items":[{"sku":"ITEM-1","qty":2}]}",
    "truncated": false,
    "originalSize": 68
  }
}
FieldDescription
originalThe payload from the event that triggered the HTTP Action
httpAction.nameName of the HTTP Action that made the request
httpAction.methodHTTP method used (GET, POST, PUT, etc.)
httpAction.urlThe URL that was called (after template interpolation)
httpResponse.statusCodeHTTP status code from the external service
httpResponse.bodyParsed JSON response body (or empty object)
httpResponse.rawRaw response string
httpResponse.truncatedtrue if the response was truncated due to plan limits
httpResponse.originalSizeOriginal byte count (only present if truncated)
Output webhooks only receive events when the HTTP Action returns a 2xx status code. If the request fails (timeout, 4xx, 5xx), no downstream event is created.

Example flow: bridging a service without webhooks

jsonFlow: Webhook A → HTTP Action → Webhook B
// 1. Webhook arrives at Webhook A with:
{ "orderId": "ord_123", "action": "check_status" }

// 2. HTTP Action is configured as:
//    GET https://api.legacy.com/orders/{{payload.orderId}}

// 3. External API responds with:
{ "orderTotal": 99.99, "status": "shipped", "trackingUrl": "https://..." }

// 4. Webhook B receives:
{
  "original": { "orderId": "ord_123", "action": "check_status" },
  "httpAction": {
    "name": "Check Order Status",
    "method": "GET",
    "url": "https://api.legacy.com/orders/ord_123"
  },
  "httpResponse": {
    "statusCode": 200,
    "body": {
      "orderTotal": 99.99,
      "status": "shipped",
      "trackingUrl": "https://..."
    },
    "raw": "..."
  }
}

Scheduled Workflow payload

Scheduled webhooks fire on a cron schedule. The payload is whatever you defined when creating the scheduled webhook — there is no fixed structure.

jsonExample — user-defined SW payload
{
  "type": "daily_report",
  "reportDate": "2024-06-01"
}

The connected webhooks receive this payload as a regular event. All downstream processing (chains, additional targets, HTTP actions) works the same as for any other event.


Email Action context

Email Actions receive the same context object as HTTP Actions. Template variables work the same way in the email subject, recipients, and body.

jsonEmail Action context (same as HTTP Action)
{
  "payload": { "type": "order.created", "orderId": "ord_123" },
  "response": {
    "status": 200,
    "body": { "processed": true },
    "raw": "..."
  },
  "chain": {         // only if triggered from a chain event
    "step": 2,
    "original": { ... },
    "previous": { ... },
    "priorResponse": { ... }
  }
}
Use templates in the email subject: Order {{payload.orderId}} processed, or in the recipient field: {{payload.customer.email}}.

Transform node context

Transform nodes receive the same base context as payload transforms: the event payload, inbound headers, and event metadata.

jsonTransform node context
{
  "payload": {
    "type": "order.created",
    "data": { "object": { "amount": 5000 } }
  },
  "headers": {
    "content-type": "application/json"
  },
  "meta": {
    "eventId": "6650a1b2c3d4e5f6a7b8c9d0",
    "webhookId": "6650a1b2c3d4e5f6a7b8c9d1",
    "attempt": "1",
    "receivedAt": "2024-06-01T12:00:00.000Z"
  }
}

Transform nodes have two modes:

  • replaceThe transform output completely replaces the payload
  • mergeThe transform output is merged into the original payload (shallow merge)

Router payload

Routers perform transparent forwarding. The destination webhook receives the exact same payload, headers, and source IP as the original event — no wrapping or modification.

Routers are useful for conditionally routing events based on rules (e.g., route type: "payment" events to Webhook A and type: "subscription" events to Webhook B). The destination webhook sees the event as if it arrived directly.

Summary table

Which context fields are available in each scenario:

ScenariopayloadresponsechainheadersmetahttpResponse
Payload transform
Additional target (forwardResponse)
Chain (success)
Chain (failure)
HTTP Action (direct)
HTTP Action (failed delivery)
HTTP Action (chain)
HTTP Action (test)
HA output webhook
Transform node
Router
Email Actionif chain
In the HA output webhook row, payload refers to original (the root event payload) and httpResponse contains the HTTP Action's response. These use different field names than the template context — they are the raw event payload delivered to the webhook.

Template variables quick reference

All template variables available inside {{...}} expressions (in payload transforms, HTTP Action URL/headers/body, and email templates):

VariableDescriptionAvailable in
{{payload.field}}Value from the webhook payload (dot-notation)All
{{payload.nested.deep.field}}Deeply nested payload valuesAll
{{headers.content-type}}Inbound request header (lowercase)Transforms
{{meta.eventId}}HostWebhook event IDTransforms
{{meta.webhookId}}Webhook IDTransforms
{{meta.attempt}}Delivery attempt numberTransforms
{{meta.receivedAt}}ISO 8601 timestampTransforms
{{response.status}}HTTP status code from primary deliveryAdditional targets, HTTP Action
{{response.body.field}}Parsed response fieldAdditional targets, HTTP Action
{{response.raw}}Raw response stringAdditional targets, HTTP Action
{{chain.step}}Current chain step numberHTTP Action (chain)
{{chain.original.field}}Root payload fieldHTTP Action (chain)
{{chain.previous.field}}Previous step's response fieldHTTP Action (chain)
{{chain.priorResponse.status}}Previous step's HTTP statusHTTP Action (chain)

Expression syntax

SyntaxExampleDescription
Null coalescing{{payload.name ?? 'Guest'}}Fallback value if field is null/undefined
Ternary{{payload.active ? 'yes' : 'no'}}Conditional value based on truthiness
Comparison{{payload.amount > 1000 ? 'large' : 'small'}}Compare with ===, !==, >, <, >=, <=
Path branches{{payload.x ? payload.x : payload.y}}Resolve field paths in branches
Pipe: json{{payload.data | json}}Serialize as JSON string
Pipe: upper{{payload.name | upper}}Uppercase string
Pipe: lower{{payload.name | lower}}Lowercase string
Pipe: trim{{payload.name | trim}}Trim whitespace

Response truncation limits

Chain responses and HTTP Action output responses are subject to size limits based on your plan tier. If a response exceeds the limit, it is truncated and the truncated flag is set to true.

PlanMax response sizeApplies to
Free8 KBChain responses, HTTP Action outputs
Pro64 KBChain responses, HTTP Action outputs
Enterprise1 MBChain responses, HTTP Action outputs
Truncated JSON may be invalid — if the response was cut mid-string or mid-object, the response.body will fall back to the raw truncated string instead of a parsed object. Always check truncated if you depend on the response structure.

Propagation depth

To prevent infinite loops (e.g., Webhook A chains to B, B chains to A), HostWebhook enforces a maximum propagation depth of 10. This applies to both chain steps and HTTP Action output webhooks.

  • Chains — each chain step increments chainStep by 1. After 10 steps, the chain stops.
  • HTTP Action outputs — each output delivery increments propagationDepth by 1. After 10 levels, no further downstream events are created.
If you hit the propagation limit, a warning is logged but no error is returned. Design your flows to stay well within this limit — deep chains are usually a sign that the architecture can be simplified.