Skip to content
mittr

Payload Transformations

Payload transformations let you reshape the URL, headers and body of a webhook before Mittr delivers it. Each endpoint can have its own transformation, written in JavaScript.

  1. An event is routed to an endpoint with a transformation configured
  2. On each delivery attempt, Mittr calls your transform function with the delivery as input
  3. The returned values are used for that attempt’s request
  4. Mittr delivers the modified request

The transformation shapes what is sent, not what is stored: the event keeps the payload your producer sent, and every attempt (including retries and replays) transforms that original again.

Transformations run in a sandboxed environment with a 1-second timeout and a 128 MB memory limit.

Set the transformation field when creating or updating an endpoint:

Terminal window
curl -X POST https://app.mittr.io/api/v1/endpoints \
-H "X-API-Key: mtr_your_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.example.com/orders",
"eventTypes": ["order.*"],
"transformation": "function transform(webhook) { return { payload: { orderId: webhook.payload.id, total: webhook.payload.amount / 100, currency: \"usd\" } }; }"
}'

Your code must define a function named transform. It receives one argument describing the delivery and must return an object.

FieldTypeDescription
webhook.payloadobjectThe event payload
webhook.headersobjectThe event’s delivery headers
webhook.urlstringThe endpoint URL
webhook.methodstringAlways POST

The event type is not part of the input. If you route on it, include it in the payload.

FieldTypeDescription
payloadany JSON valueReplaces the body for this attempt
urlstringReplaces the endpoint URL for this attempt. The usual delivery protections (SSRF blocking, IP allow/block lists) still apply
headersobjectReplaces the event’s headers for this attempt. To add a header, return { ...webhook.headers, "X-New": "value" }
cancelbooleantrue skips the delivery. The event is marked delivered and no request is sent

All fields are optional: an omitted field keeps the input’s value. Deliveries are always sent as POST; a returned method is ignored. Signature headers are added after the transformation, over the transformed body.

function transform(webhook) {
const p = webhook.payload;
return {
payload: {
id: p.orderId,
customer: p.customerEmail,
items: p.lineItems.map(i => ({ sku: i.sku, qty: i.quantity })),
total: p.totalCents / 100
}
};
}
function transform(webhook) {
return {
headers: { ...webhook.headers, "X-Tenant-ID": webhook.payload.tenantId }
};
}
// Only deliver high-value orders
function transform(webhook) {
if (webhook.payload.amount < 10000) {
return { cancel: true };
}
return { payload: { ...webhook.payload, priority: "high" } };
}
function transform(webhook) {
const routes = {
"order.created": "https://api.example.com/orders",
"customer.created": "https://api.example.com/customers"
};
// The event type has to travel in the payload: it is not an input field.
return { url: routes[webhook.payload.type] || webhook.url };
}
LimitValue
Execution timeout1 second
Memory limit128 MB

If the script throws, times out, exceeds the memory limit, or returns something other than an object, the error is logged and the attempt is sent with the original, untransformed request.