Transformations and Payload Shaping
Use mask, replace, delete, type-cast, and regex rules to shape outgoing content.
PayloadRelay can change the incoming payload before the delivery. A transform rule applies to each accepted request, after the field validation and before the delivery. The formatting for each destination then adapts the changed payload.
Purpose#
Use this guide to:
- Mask a sensitive field, such as a credit card number and an email address, before the delivery.
- Replace a field value with fixed data.
- Remove a field that the delivery must not contain.
- Change a field type, such as a string to a number, or a string to a boolean.
- Apply a regular expression substitution to a payload.
- Add fields with fixed values to the payload.
- Configure the formatting and the field selection for an email, Slack, Discord, Microsoft Teams, Telegram, and Google Sheets target.
Before you start#
- Make sure that you can edit the endpoint.
- Attach one relay target as a minimum.
Transform rules#
A transform rule changes the payload on the endpoint. Every destination receives the changed version. PayloadRelay applies the rules in order. To change the order, use the up control and the down control.
Field selector syntax#
Each rule uses a selector expression to identify a specific field:
| Format | Selector example | Resolves to |
|---|---|---|
| JSON | user.email, items.0.name | A dot path into the JSON body. A numeric segment gives the index in an array. PayloadRelay does not support the bracket notation. |
Form-encoded / query params | email, name | A top-level parsed field |
XML | /root/item/@id, //item/price/text(), $ | A selector in the XPath subset for XML, or $ for a transform on the complete body text. PayloadRelay uses a literal substring only when malformed XML falls back to plain text. |
Plain text | $, secret-token | $ for the complete body, or a literal substring to match |
A selector has a maximum of 200 characters. PayloadRelay ignores a missing field and a missing intermediate path, and it does not reject the request.
A MASK, REGEX, or TYPE_CAST rule changes a value that is a string, a number, a boolean, or null. If the selected value is a JSON object or a JSON array, MASK and REGEX keep the value with no change. For TYPE_CAST on an object or an array, read the TYPE_CAST section.
XPath subset for XML#
An XML selector uses a small part of XPath. PayloadRelay evaluates this subset in a time that is linear in the size of the payload. The same subset applies to an XML transform selector, an XML field validation rule, and an XML captcha field name.
- A selector is one path.
|can join two or more paths. - A path can start with
/or//. A/or a//separates two steps. - A step is an element name,
*,@attribute,@*,text(),., or... - A step other than
.and..can have one or more conditions. A condition is a position such as[1]or[last()], or a test of the node. A position starts at 1. - A test uses
.,@name, the name of a child element,text(),local-name(), orname(). The test can use this value alone, or compare it with a quoted value through=or!=. For example:[@name],[@name='value'],[name!='value'], or[.='value']. - A test can also be
contains(value, 'text')orstarts-with(value, 'text').and,or, andnot()join two tests. - A field validation rule and a captcha field name can also count the nodes, for example
count(//item). A transform selector cannot usecount(), because a transform changes nodes. - A condition cannot contain a path, for example
[b/c='x']or[.//x]. The subset does not include other functions, axes such asancestor::, numeric comparisons, operators, or variables.
Examples are /order/id, //item/@id, //item/price/text(), //item[@type='total']/price, /order//sku | /order/id, and //item[last()].
If a selector is outside the subset, PayloadRelay rejects the configuration when you save it. The error message names the supported forms. An older configuration can contain a selector outside the subset. PayloadRelay does not run that selector at relay time. It rejects the request with HTTP 400, and Activity records Unsupported Selector (UNSUPPORTED_SELECTOR). Thus PayloadRelay does not send a value that the rule must mask, replace, or delete. The error reason names the rule type: a transform rule, a field validation rule, or the captcha field name. To correct the rule, change the selector and save the endpoint. An UNSUPPORTED_SELECTOR outcome does not count toward auto-pause.
An XML transform selector is a literal substring for the plain-text fallback if it contains no /, [, ], or @, does not start with ., and has no axis name before ::. For example, std::string and fe80::1 are literal substrings.
An XML payload can have a maximum of 100 nested element levels. A webhook request with more levels returns HTTP 400 and records MALFORMED_XML_PAYLOAD. For an email body with more levels, PayloadRelay applies the transforms as plain text.
Rule types#
MASK: hide sensitive values
Replace a field value with mask characters. You can change the mask length.
| Setting | Description |
|---|---|
| Field selector | The field to mask |
| Mask character | The character used for masking. The default is *. |
| Randomize length | Changes the mask length, and an observer cannot then calculate the length of the original value. |
maskChar is * by default. If you give a value, it must be exactly one non-control character. An emoji, such as 🔒, is one character. With the randomize length control enabled, the mask is 1 to 8 characters. If the control is disabled, the mask length is the same as the string form of the field. So the length information stays.
MASK replaces the complete value. It cannot keep a part of the value.
Example: mask a credit card number.
Field: cardNumber
Type: MASK
Char: *
Input: "4111-1111-1111-1234"
Result: "*******************"To keep the last 4 digits, use a REGEX rule instead of MASK:
Field: cardNumber
Type: REGEX
Pattern: \d(?=(?:\D*\d){4})
Replacement: *
Input: "4111-1111-1111-1234"
Result: "****-****-****-1234"REPLACE: replace field values
Replace the current value of a field with a new value.
| Setting | Description |
|---|---|
| Field selector | The field to replace |
| Replace value | The literal text to use |
| Value type | TEXT, NUMBER, BOOLEAN, or NULL. This controls the JSON value type. |
For a JSON, form, or query payload, a NUMBER replacement must parse as a number. A BOOLEAN replacement must be true or false. PayloadRelay rejects an invalid value when you save the endpoint. NULL sets the field to JSON null, and it does not delete the field.
Examples:
- Replace an environment tag: set
envtoproduction(type: TEXT). - Set a numeric field: set
priorityto1(type: NUMBER). - Set a field to null: set
debugInfoto null (type: NULL).
Remove a field from the payload. The field does not appear in a delivery. For an array, a numeric selector such as items.1 removes that array element, and it moves the later entries to the left.
For an XML payload, an XPath attribute selector, such as //item/@secret, removes that attribute from its element.
| Setting | Description |
|---|---|
| Field selector | The field to remove |
Example: remove internal metadata before forwarding.
Field: _internalRequestId
Type: DELETETYPE_CAST: change the data type
Change a field value to a different JSON type. Use this rule when the sender sends strings and the receiver needs typed values.
| Setting | Description |
|---|---|
| Field selector | The field to cast |
| Cast to | The target type: TEXT, NUMBER, BOOLEAN, or NULL |
Examples:
- Cast to NUMBER:
"42"(string) becomes42(number). - Cast to BOOLEAN:
"true"(string) becomestrue(boolean). - Cast to TEXT:
"hello"(string) stays"hello"(string, with no change).
If PayloadRelay cannot parse the value as the target type, for example, "abc" cast to NUMBER, it sets the field to null. TYPE_CAST is not available for an XML payload or a plain-text payload.
If the selected value is a JSON object or a JSON array:
- A cast to TEXT writes the compact JSON text of the value as a string. For example,
{"a": 1}becomes"{\"a\":1}". - A cast to NULL sets the field to
null. - A cast to NUMBER or BOOLEAN keeps the value with no change.
Apply a regular expression find-and-replace operation to a text value of a field. A pattern uses the Java-compatible syntax. PayloadRelay examines the pattern and the replacement when you save them. At the delivery, the replacements apply to all the matches, with multiline behavior and dot-matches-newline behavior, the $1 and $2 group references, and a 1-second safety timeout. If a replacement fails or times out, PayloadRelay keeps the original value.
| Setting | Description |
|---|---|
| Field selector | The field for the regular expression |
| Regex pattern | A Java-compatible regular expression |
| Replacement | A replacement string that supports $1 and $2 back references |
The replacement uses the Java replacement syntax:
$1,$2, and the other numbers refer to a capture group in the pattern.${name}refers to a named group, such as(?<name>...). The group must exist in the pattern.- To write a literal
$, write\$. To write a literal backslash, write\\. - A backslash at the end of the replacement is not valid.
If the replacement is not valid for the pattern, the API rejects the endpoint with a 400 error when you save it.
For a plain-text payload with a substring selector, the pattern runs on the selected substring. PayloadRelay then replaces every occurrence of that substring in the body with the result. With the $ selector, the pattern runs on the complete body.
Example: normalize phone numbers by removing non-digit characters.
Field: phoneNumber
Pattern: [^0-9]
Replacement: (empty)
Result: "+15551234567" → "15551234567"Append fields#
An append field adds endpoint data after the transform rules apply. Every destination receives the payload with the added fields. The added fields are available to a webhook body, the routing, the outbound HMAC signing, Google Sheets, the email formatting, and the message templates.
| Setting | Description |
|---|---|
| Field name | A JSON, form, or query dot path such as metadata.source or items.0.id. For XML, use an element name. A plain-text payload ignores this field. |
| Value | The literal value to add |
| Value type | TEXT, NUMBER, BOOLEAN, or NULL for a JSON, form, or query payload |
Behavior and limits:
- An endpoint can have a maximum of 20 append rules.
- A field name has a maximum of 200 characters. A value has a maximum of 65,536 characters.
- A JSON, form, and query payload needs a valid dot path. PayloadRelay rejects a duplicate append field name. An append rule writes over an existing field at that path.
NUMBERsupports an integer, a decimal, and scientific notation. PayloadRelay rejects an invalid number when you save.BOOLEANmust betrueorfalse.NULLwrites an actual JSON null, and it ignores the value field.- An XML append rule adds a child element to the root element. It adds raw text when the element name is blank. If a DELETE rule removed the root element, PayloadRelay skips the XML append rules. A plain-text rule adds the literal value to the end of the body.
- A numeric segment in a JSON field name selects an element of an existing array. For example,
items.0.flagsetsflagon the first element ofitems. If that element is a string, a number, a boolean, or null, PayloadRelay replaces it with an object that holds the new field. If the index is negative, is not in the array, or the segment is not a number, PayloadRelay skips the rule. An append rule never replaces an array with an object. - A
Nonepayload and a bodylessGETorHEADendpoint clear the append rules. A query-parameter format can use the append rules, because it makes a JSON payload. - A JSON array root and a JSON scalar root cannot receive appended fields. To append structured fields, use a JSON object payload.
Size of the transformed payload#
The transform rules and the append rules cannot make the payload larger than the payload size limit of the plan. For example, a REPLACE rule with a one-character selector and a long value can make a payload many times larger. If the result is larger than the limit, PayloadRelay rejects the request with 413. Activity records PAYLOAD_TOO_LARGE, and PayloadRelay sends nothing to the destinations.
Per-output formatting#
After the transforms apply, each destination formats the payload for its destination type. Configure these values for each destination in the Outputs tab.
Email outputs#
| Body format | Description |
|---|---|
RAW_PAYLOAD | The raw JSON, form, or XML payload, with formatting. A text payload or an XML payload arrives as its text, without JSON quotes. |
RAW_PAYLOAD_ROWS | One field in each row, with an indentation of two spaces for each level of the nested objects and arrays. This format has no custom template. |
TEXT | Plain text, with an optional custom body template that supports template variables |
HTML | HTML, with an optional custom body template that supports template variables |
For RAW_PAYLOAD_ROWS, an XML payload uses its own structure. A text/plain payload stays raw text.
An HTML custom template escapes each value that it inserts, also {{email.htmlBody}}. So a payload value cannot add markup to the email. PayloadRelay does not change the markup that you write in the template. It does not remove a javascript: link from that markup.
Slack outputs#
- The Markdown control: when it is enabled, Slack applies the mrkdwn formatting, such as
*bold*and_italic_. This applies to the Slack text that PayloadRelay creates and to the body sections of a message template. Slack-nativetext,blocks, orattachmentsfrom the sender keep their own text and their own formatting rules. - PayloadRelay escapes
&,<, and>in the text that it creates from the payload. When the Markdown control is enabled, PayloadRelay also escapes these characters in each value that a template inserts. So a payload value cannot mention@channelor a user, and it cannot add a<url|text>link. A mention or a link works only in the literal text of the template.
Discord outputs#
- The TTS (Text-to-Speech) control: when it is enabled, Discord speaks the messages. Use it for an urgent alert.
- The control that cuts a long message: it is disabled by default. When it is disabled, Activity records Discord content above the Discord 2000-character limit as a failed delivery. When it is enabled, PayloadRelay makes the content shorter before it sends the message. A message template does not use this control. Refer to Rich Message Templates.
- A message that PayloadRelay creates sets
allowed_mentionsto{"parse": []}. So a payload value cannot mention@everyone, a role, or a user. A payload in the Discord message shape keeps its ownallowed_mentions.
Transform order and behavior#
- The request arrives and passes the inbound authentication, the rate limits, the body filters, the captcha test, and the field validation.
- PayloadRelay removes the captcha fields that the configuration excludes.
- PayloadRelay applies the transform rules in the configured order, from the top to the bottom. A later rule uses the earlier results.
- The append field rules apply after the transforms. They can write over a field that an earlier rule changed or removed.
- PayloadRelay uses the payload with the transforms and the appended fields for the routing, the outbound HMAC signing, the formatting for each destination, and the delivery.
- Each destination applies its own formatting, such as an email body or the Slack Markdown.
An empty plain-text body or an empty XML body stays empty after the transforms. It does not become the text null.
An accepted activity log does not store a request body, original or transformed. A delivery attempt uses the transformed payload. When the transforms are configured, PayloadRelay does not send the original raw body for a failover.
The transforms change the payload one time, on the endpoint. The values for each destination only format the result. They cannot change the individual fields again. For destination-specific content, use message templates on a Slack, Discord, Teams, or Telegram destination. You can also use routing filters for different destinations.
Expected result#
- PayloadRelay masks or removes a sensitive field before the delivery.
- The field types agree with the downstream systems.
- An email message uses the selected body format.
- A Slack message obeys
Enable Markdown formatting. A Discord message obeysSend as text-to-speech (TTS). A generated Discord message also obeysTruncate long messages.
Common issues and fixes#
- PayloadRelay does not apply the transform: make sure that the field selector is correct. A JSON path uses the dot notation (
user.email,items.0.name), XML uses the XPath subset for XML, andtext/plainuses$or a plain substring match. - A CAST to NUMBER fails with no message: a value that is not a number, such as
"abc", becomesnull. If you need a fallback value, use a REPLACE rule. - The email body is wrong: change the body format (
RAW_PAYLOAD, orTEXTwith a template), and read the preview before you save. - The Slack formatting fails: turn on Markdown for the destination, and use the Slack mrkdwn syntax, not the standard Markdown.
- The regex group references fail: use the Java syntax
$1and$2, and not the Python syntax\1and\2. - The API rejects a REGEX rule with
Regex transform replacement is invalid.: the replacement has an error. It refers to a group that the pattern does not have, or it has a$or a backslash that is not escaped. Write\$for a literal dollar sign.
Related guides#
- Endpoint Management
- HTTP Methods and Payload Formats
- Routing Filters: send different payloads to different targets.
- Message Templates: format a Slack, Discord, Teams, and Telegram message.
- Observability
- Troubleshooting